Repository: knative/serving
Pull request #8155 (2020-06-01 21:40:20)

Automatically bump ObservedGeneration for PA types
<!--
Request Prow to automatically lint any go code in this PR:

/lint
-->

Issue #4937

<!-- Please include the 'why' behind your changes if no issue exists -->
## Proposed Changes

* Use common logic to automatically bump ObservedGeneration for PA types


**Note**
This change depends on https://github.com/knative/serving/pull/8105 to work properly. The automatic logic in preprocess resets ready to unknown upon observing a new generation (expecting the reconciler to overwrite it with something), but the scaler logic here: https://github.com/knative/serving/blob/224721105fb411d354d07a77fb322939696a42ac/pkg/reconciler/autoscaling/kpa/scaler.go#L193 mixes the ready and active conditions.

**Release Note**

<!-- Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". -->

```release-note

```


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

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/8155#" title="Author self-approved">whaught</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **markusthoemmes**
You can assign the PR to them by writing `/assign @markusthoemmes` 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:

- **[OWNERS](https://github.com/knative/serving/blob/master/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":["markusthoemmes"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/autoscaling/hpa/hpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1267571826960109570/artifacts/line-cov.html#file1) | 97.2% | 97.1% | -0.1
[pkg/reconciler/autoscaling/kpa/kpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1267571826960109570/artifacts/line-cov.html#file2) | 93.8% | 93.7% | -0.1

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | 1cd47e48f4e3d276ff91d085da13e951ee23295f | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267571826960109572) | `/test pull-knative-serving-integration-tests`

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

<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 -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]1cd47e48f4e3d276ff91d085da13e951ee23295f[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests | [pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267571826960109572) | 1/3

Automatically retrying due to test flakiness...
/test pull-knative-serving-integration-tests
knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | 1cd47e48f4e3d276ff91d085da13e951ee23295f | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267582521705500672) | `/test pull-knative-serving-integration-tests`

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

<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 -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]1cd47e48f4e3d276ff91d085da13e951ee23295f[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests | [pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267571826960109572)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267582521705500672) | 2/3

Automatically retrying due to test flakiness...
/test pull-knative-serving-integration-tests
knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | 1cd47e48f4e3d276ff91d085da13e951ee23295f | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267593470030123008) | `/test pull-knative-serving-integration-tests`

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

<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 -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]1cd47e48f4e3d276ff91d085da13e951ee23295f[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests | [pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267571826960109572)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267582521705500672)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267593470030123008) | 3/3

Automatically retrying due to test flakiness...
/test pull-knative-serving-integration-tests
knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | 1cd47e48f4e3d276ff91d085da13e951ee23295f | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267604415901077504) | `/test pull-knative-serving-integration-tests`

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

<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 -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]1cd47e48f4e3d276ff91d085da13e951ee23295f[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests | [pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267571826960109572)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267582521705500672)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267593470030123008)<br>[pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267604415901077504) | 3/3

Job pull-knative-serving-integration-tests expended all 3 retries without success.
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/autoscaling/hpa/hpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1267634111724392451/artifacts/line-cov.html#file2) | 97.2% | 97.1% | -0.1
[pkg/reconciler/autoscaling/kpa/kpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1267634111724392451/artifacts/line-cov.html#file3) | 93.8% | 93.7% | -0.1

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | 8752f545ef6eb02c14c6a58e11e74b6cde0ad909 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-integration-tests/1267634111724392449) | `/test pull-knative-serving-integration-tests`

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

<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 -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]8752f545ef6eb02c14c6a58e11e74b6cde0ad909[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests |  | 0/3

Failed non-flaky tests preventing automatic retry of pull-knative-serving-integration-tests:

```
test/scale.TestScaleToN
```
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/autoscaling/hpa/hpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1268083771941326850/artifacts/line-cov.html#file2) | 97.2% | 97.1% | -0.1
[pkg/reconciler/autoscaling/kpa/kpa.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8155/pull-knative-serving-go-coverage/1268083771941326850/artifacts/line-cov.html#file3) | 93.8% | 93.7% | -0.1


Patch:
diff --git a/go.mod b/go.mod
index f4d3a070d..7773514f3 100644
--- a/go.mod
+++ b/go.mod
@@ -43,8 +43,8 @@ require (
 	k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
 	k8s.io/metrics v0.17.6
 	knative.dev/caching v0.0.0-20200521155757-e78d17bc250e
-	knative.dev/pkg v0.0.0-20200528190300-08a86da47d28
-	knative.dev/test-infra v0.0.0-20200528222301-350178ab2a0e
+	knative.dev/pkg v0.0.0-20200603004717-9d862737e5c1
+	knative.dev/test-infra v0.0.0-20200602194317-2a31597e0f46
 )
 
 // pin the older grpc - see: https://github.com/grpc/grpc-go/issues/3180
diff --git a/go.sum b/go.sum
index 4feb2f05d..d4f70f75c 100644
--- a/go.sum
+++ b/go.sum
@@ -1319,10 +1319,9 @@ knative.dev/pkg v0.0.0-20200515002500-16d7b963416f/go.mod h1:tMOHGbxtRz8zYFGEGpV
 knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7 h1:9S2r59HZJF9nKvoRLg5zJzx6XpVlVyvVRqz/C/h6h2s=
 knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA=
 knative.dev/pkg v0.0.0-20200520073958-94316e20e860/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA=
-knative.dev/pkg v0.0.0-20200527024749-495174c96651 h1:/LhCktTMhJrCDXGg3KCWeSQTLLGy3Ms4AaqM9O/05dI=
-knative.dev/pkg v0.0.0-20200527024749-495174c96651/go.mod h1:4ipprwHqpqiyYHbrEjSf1kNwL+sJOqHhj1ujO2WxvpE=
-knative.dev/pkg v0.0.0-20200528190300-08a86da47d28 h1:tLWWfrpGYT8vs/QLWYc7s0pqaw+ISz4UmM9AhrWBc8o=
-knative.dev/pkg v0.0.0-20200528190300-08a86da47d28/go.mod h1:ywZfX/0D8hoOf4uJVgeEvJpSmsOauQvr1IuAWld9UjM=
+knative.dev/pkg v0.0.0-20200601184204-18c577c87d4f/go.mod h1:ywZfX/0D8hoOf4uJVgeEvJpSmsOauQvr1IuAWld9UjM=
+knative.dev/pkg v0.0.0-20200603004717-9d862737e5c1 h1:RdPH0bgm61DQ/azXkQq04pwFnaHH9xSL5yJ9+X2nuiQ=
+knative.dev/pkg v0.0.0-20200603004717-9d862737e5c1/go.mod h1:8IfPj/lpuKHHg82xZCl2wuFZ3BM96To72sN1W8T9wjQ=
 knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ=
 knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU=
 knative.dev/test-infra v0.0.0-20200513011557-d03429a76034 h1:JxqONCZVS7or+Fv3ebVQoipuIBH7Ig3Qbx170hgIF+A=
@@ -1333,8 +1332,8 @@ knative.dev/test-infra v0.0.0-20200519161858-554a95a37986 h1:ZDy43jkWPQ75d4l4DGy
 knative.dev/test-infra v0.0.0-20200519161858-554a95a37986/go.mod h1:LeNa1Wvn47efeQUkpkn3XG7Fx9Ga+rhAP13SZyjaEGg=
 knative.dev/test-infra v0.0.0-20200522180958-6a0a9b9d893a h1:c0qTABRcNoxZVu5gsryLWPZtGa/s4zsvovz0nGefuzg=
 knative.dev/test-infra v0.0.0-20200522180958-6a0a9b9d893a/go.mod h1:n9eQkzmSNj8BiqNFl1lzoz68D09uMeJfyOjc132Gbik=
-knative.dev/test-infra v0.0.0-20200528222301-350178ab2a0e h1:ZzmzPgCKdrFg2MA2sGtd9HrlIQ7XidnmMJB8RDEduO0=
-knative.dev/test-infra v0.0.0-20200528222301-350178ab2a0e/go.mod h1:7JtOmoYiYxh2oFO23nwGanuJ6qT6mFrRlZV1LL6gomY=
+knative.dev/test-infra v0.0.0-20200602194317-2a31597e0f46 h1:xXewx8AeTeNKIsqUwUJ24RF0xOVm3EQ0t7vBmM+RgB4=
+knative.dev/test-infra v0.0.0-20200602194317-2a31597e0f46/go.mod h1:JV4E61erdHLn4jT0X+svUP7lZYggJyXMCGDewTSQuO8=
 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/apis/autoscaling/v1alpha1/pa_lifecycle.go b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
index c0f48dfa4..bcc6b8347 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
@@ -174,7 +174,7 @@ func (pas *PodAutoscalerStatus) GetCondition(t apis.ConditionType) *apis.Conditi
 	return podCondSet.Manage(pas).GetCondition(t)
 }
 
-// InitializeConditions initializes the conditionhs of the PA.
+// InitializeConditions initializes the conditions of the PA.
 func (pas *PodAutoscalerStatus) InitializeConditions() {
 	podCondSet.Manage(pas).InitializeConditions()
 }
diff --git a/pkg/apis/autoscaling/v1alpha1/pa_types.go b/pkg/apis/autoscaling/v1alpha1/pa_types.go
index e38cbfaa9..d55de277e 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_types.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_types.go
@@ -26,7 +26,7 @@ import (
 )
 
 // +genclient
-// +genreconciler:class=autoscaling.knative.dev/class
+// +genreconciler:class=autoscaling.knative.dev/class,krshapedlogic=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // PodAutoscaler is a Knative abstraction that encapsulates the interface by which Knative
diff --git a/pkg/client/injection/reconciler/autoscaling/v1alpha1/podautoscaler/reconciler.go b/pkg/client/injection/reconciler/autoscaling/v1alpha1/podautoscaler/reconciler.go
index e96835c03..241318922 100644
--- a/pkg/client/injection/reconciler/autoscaling/v1alpha1/podautoscaler/reconciler.go
+++ b/pkg/client/injection/reconciler/autoscaling/v1alpha1/podautoscaler/reconciler.go
@@ -175,10 +175,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
 			logger.Warnw("Failed to set finalizers", zap.Error(err))
 		}
 
+		reconciler.PreProcessReconcile(ctx, resource)
+
 		// Reconcile this copy of the resource and then write back any status
 		// updates regardless of whether the reconciliation errored out.
 		reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
 
+		reconciler.PostProcessReconcile(ctx, resource)
+
 	} else if fin, ok := r.reconciler.(Finalizer); ok {
 		// Append the target method to the logger.
 		logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
diff --git a/pkg/http/handler/timeout.go b/pkg/http/handler/timeout.go
index 09efbeb52..1be9072f1 100644
--- a/pkg/http/handler/timeout.go
+++ b/pkg/http/handler/timeout.go
@@ -89,7 +89,7 @@ func (h *timeToFirstByteTimeoutHandler) ServeHTTP(w http.ResponseWriter, r *http
 			}
 			return
 		case <-timeout.C:
-			if tw.TimeoutAndWriteError(h.body) {
+			if tw.timeoutAndWriteError(h.body) {
 				return
 			}
 		}
@@ -112,7 +112,6 @@ type timeoutWriter struct {
 }
 
 var _ http.Flusher = (*timeoutWriter)(nil)
-
 var _ http.ResponseWriter = (*timeoutWriter)(nil)
 
 func (tw *timeoutWriter) Flush() {
@@ -158,13 +157,13 @@ func (tw *timeoutWriter) WriteHeader(code int) {
 	tw.w.WriteHeader(code)
 }
 
-// TimeoutAndError writes an error to the response write if
+// timeoutAndError writes an error to the response write if
 // nothing has been written on the writer before. Returns whether
 // an error was written or not.
 //
 // If this writes an error, all subsequent calls to Write will
 // result in http.ErrHandlerTimeout.
-func (tw *timeoutWriter) TimeoutAndWriteError(msg string) bool {
+func (tw *timeoutWriter) timeoutAndWriteError(msg string) bool {
 	tw.mu.Lock()
 	defer tw.mu.Unlock()
 
diff --git a/pkg/reconciler/autoscaling/hpa/hpa.go b/pkg/reconciler/autoscaling/hpa/hpa.go
index c60b589c6..b779223af 100644
--- a/pkg/reconciler/autoscaling/hpa/hpa.go
+++ b/pkg/reconciler/autoscaling/hpa/hpa.go
@@ -108,7 +108,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, pa *pav1alpha1.PodAutosc
 		pa.Status.MarkActive()
 	}
 
-	pa.Status.ObservedGeneration = pa.Generation
 	pa.Status.DesiredScale = ptr.Int32(hpa.Status.DesiredReplicas)
 	pa.Status.ActualScale = ptr.Int32(hpa.Status.CurrentReplicas)
 	return nil
diff --git a/pkg/reconciler/autoscaling/kpa/kpa.go b/pkg/reconciler/autoscaling/kpa/kpa.go
index 818cdc2f5..7e6d94587 100644
--- a/pkg/reconciler/autoscaling/kpa/kpa.go
+++ b/pkg/reconciler/autoscaling/kpa/kpa.go
@@ -210,7 +210,6 @@ func computeStatus(pa *pav1alpha1.PodAutoscaler, pc podCounts, logger *zap.Sugar
 	computeActiveCondition(pa, pc)
 	logger.Debugf("PA Status after reconcile: %#v", pa.Status.Status)
 
-	pa.Status.ObservedGeneration = pa.Generation
 	return nil
 }
 
diff --git a/vendor/knative.dev/pkg/configmap/example.go b/vendor/knative.dev/pkg/configmap/example.go
new file mode 100644
index 000000000..ee17666b7
--- /dev/null
+++ b/vendor/knative.dev/pkg/configmap/example.go
@@ -0,0 +1,34 @@
+/*
+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 configmap
+
+import (
+	"hash/crc32"
+)
+
+const (
+	// ExampleKey signifies a given example configuration in a ConfigMap.
+	ExampleKey = "_example"
+
+	// ExampleChecksumLabel is the label that stores the computed checksum.
+	ExampleChecksumLabel = "knative.dev/example-checksum"
+)
+
+// Checksum generates a checksum for the example value to be compared against a respective label.
+func Checksum(value string) uint32 {
+	return crc32.ChecksumIEEE([]byte(value))
+}
diff --git a/vendor/knative.dev/pkg/configmap/store.go b/vendor/knative.dev/pkg/configmap/store.go
index a994601ab..ee643311b 100644
--- a/vendor/knative.dev/pkg/configmap/store.go
+++ b/vendor/knative.dev/pkg/configmap/store.go
@@ -23,9 +23,6 @@ import (
 	corev1 "k8s.io/api/core/v1"
 )
 
-// ExampleKey signifies a given example configuration in a ConfigMap.
-const ExampleKey = "_example"
-
 // Logger is the interface that UntypedStore expects its logger to conform to.
 // UntypedStore will log when updates succeed or fail.
 type Logger interface {
diff --git a/vendor/knative.dev/pkg/controller/controller.go b/vendor/knative.dev/pkg/controller/controller.go
index 15496b8a9..3981c5820 100644
--- a/vendor/knative.dev/pkg/controller/controller.go
+++ b/vendor/knative.dev/pkg/controller/controller.go
@@ -18,6 +18,7 @@ package controller
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"sync"
 	"time"
@@ -448,7 +449,7 @@ func (c *Impl) processNextWorkItem() bool {
 func (c *Impl) handleErr(err error, key types.NamespacedName) {
 	c.logger.Errorw("Reconcile error", zap.Error(err))
 
-	// Re-queue the key if it's an transient error.
+	// Re-queue the key if it's a transient error.
 	// We want to check that the queue is shutting down here
 	// since controller Run might have exited by now (since while this item was
 	// being processed, queue.Len==0).
@@ -483,8 +484,8 @@ func (c *Impl) FilteredGlobalResync(f func(interface{}) bool, si cache.SharedInf
 }
 
 // NewPermanentError returns a new instance of permanentError.
-// Users can wrap an error as permanentError with this in reconcile,
-// when he does not expect the key to get re-queued.
+// Users can wrap an error as permanentError with this in reconcile
+// when they do not expect the key to get re-queued.
 func NewPermanentError(err error) error {
 	return permanentError{e: err}
 }
@@ -495,16 +496,21 @@ type permanentError struct {
 	e error
 }
 
-// IsPermanentError returns true if given error is permanentError
+// IsPermanentError returns true if the given error is a permanentError or
+// wraps a permanentError.
 func IsPermanentError(err error) bool {
-	switch err.(type) {
-	case permanentError:
-		return true
-	default:
-		return false
-	}
+	return errors.Is(err, permanentError{})
+}
+
+// Is implements the Is() interface of error. It returns whether the target
+// error can be treated as equivalent to a permanentError.
+func (permanentError) Is(target error) bool {
+	_, ok := target.(permanentError)
+	return ok
 }
 
+var _ error = permanentError{}
+
 // Error implements the Error() interface of error.
 func (err permanentError) Error() string {
 	if err.e == nil {
@@ -514,6 +520,12 @@ func (err permanentError) Error() string {
 	return err.e.Error()
 }
 
+// Unwrap implements the Unwrap() interface of error. It returns the error
+// wrapped inside permanentError.
+func (err permanentError) Unwrap() error {
+	return err.e
+}
+
 // Informer is the group of methods that a type must implement to be passed to
 // StartInformers.
 type Informer interface {
diff --git a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
index 87bb722a2..e4c2d08dc 100644
--- a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
+++ b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
@@ -102,10 +102,13 @@ func init() {
 
 func newOpencensusSDExporter(o stackdriver.Options) (view.Exporter, error) {
 	e, err := stackdriver.NewExporter(o)
-	if err == nil {
-		// Start the exporter.
-		// TODO(https://github.com/knative/pkg/issues/866): Move this to an interface.
-		e.StartMetricsExporter()
+	if err != nil {
+		return nil, err
+	}
+	// Start the exporter.
+	// TODO(https://github.com/knative/pkg/issues/866): Move this to an interface.
+	if err := e.StartMetricsExporter(); err != nil {
+		return nil, err
 	}
 	return e, nil
 }
diff --git a/vendor/knative.dev/pkg/reconciler/reconcile_common.go b/vendor/knative.dev/pkg/reconciler/reconcile_common.go
index cc0e2d712..6a32c06f7 100644
--- a/vendor/knative.dev/pkg/reconciler/reconcile_common.go
+++ b/vendor/knative.dev/pkg/reconciler/reconcile_common.go
@@ -32,6 +32,8 @@ func PreProcessReconcile(ctx context.Context, resource duckv1.KRShaped) {
 	if newStatus.ObservedGeneration != resource.GetGeneration() {
 		condSet := resource.GetConditionSet()
 		manager := condSet.Manage(newStatus)
+		// Ensure conditions are initialized before we modify.
+		manager.InitializeConditions()
 
 		// Reset Ready/Successful to unknown. The reconciler is expected to overwrite this.
 		manager.MarkUnknown(condSet.GetTopLevelConditionType(), failedGenerationBump, "unsuccessfully observed a new generation")
diff --git a/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go b/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go
index 8a3cd693c..8cc150b0a 100644
--- a/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go
+++ b/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go
@@ -184,6 +184,15 @@ func (ac *reconciler) validate(ctx context.Context, req *admissionv1beta1.Admiss
 		}
 	}
 
+	exampleData, hasExampleData := newObj.Data[configmap.ExampleKey]
+	exampleChecksum, hasExampleChecksumLabel := newObj.Labels[configmap.ExampleChecksumLabel]
+	if hasExampleData && hasExampleChecksumLabel &&
+		exampleChecksum != fmt.Sprint(configmap.Checksum(exampleData)) {
+		return fmt.Errorf(
+			"%q modified, you likely wanted to create an unindented configuration",
+			configmap.ExampleKey)
+	}
+
 	var err error
 	if constructor, ok := ac.constructors[newObj.Name]; ok {
 
diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go
index ef7c238da..869269b46 100644
--- a/vendor/knative.dev/pkg/webhook/webhook.go
+++ b/vendor/knative.dev/pkg/webhook/webhook.go
@@ -73,13 +73,6 @@ const (
 	Connect Operation = admissionv1beta1.Connect
 )
 
-var (
-	// GracePeriod is the duration that the webhook will wait after it's
-	// context is cancelled (and probes are failing) before shutting down
-	// the http server.
-	GracePeriod = 30 * time.Second
-)
-
 // Webhook implements the external webhook for validation of
 // resources and configuration.
 type Webhook struct {
@@ -145,7 +138,7 @@ func New(
 		Logger:       logger,
 		synced:       cancel,
 		stopCh:       make(chan struct{}),
-		gracePeriod:  GracePeriod,
+		gracePeriod:  network.DefaultDrainTimeout,
 	}
 
 	webhook.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0bdbfa660..77f1cc7f8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1197,7 +1197,7 @@ 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/pkg v0.0.0-20200528190300-08a86da47d28
+# knative.dev/pkg v0.0.0-20200603004717-9d862737e5c1
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate
@@ -1313,7 +1313,7 @@ knative.dev/pkg/webhook/resourcesemantics/conversion
 knative.dev/pkg/webhook/resourcesemantics/defaulting
 knative.dev/pkg/webhook/resourcesemantics/validation
 knative.dev/pkg/websocket
-# knative.dev/test-infra v0.0.0-20200528222301-350178ab2a0e
+# knative.dev/test-infra v0.0.0-20200602194317-2a31597e0f46
 ## explicit
 knative.dev/test-infra/scripts
 # sigs.k8s.io/structured-merge-diff/v2 v2.0.1


Test patch:
diff --git a/pkg/autoscaler/scaling/multiscaler_test.go b/pkg/autoscaler/scaling/multiscaler_test.go
index 2a3896160..56bdd7de2 100644
--- a/pkg/autoscaler/scaling/multiscaler_test.go
+++ b/pkg/autoscaler/scaling/multiscaler_test.go
@@ -435,12 +435,6 @@ func (u *fakeUniScaler) Scale(context.Context, time.Time) ScaleResult {
 	return ScaleResult{u.replicas, u.surplus, u.numActivators, u.scaled}
 }
 
-func (u *fakeUniScaler) getScaleCount() int {
-	u.mutex.RLock()
-	defer u.mutex.RUnlock()
-	return u.scaleCount
-}
-
 func (u *fakeUniScaler) setScaleResult(replicas, surplus, na int32, scaled bool) {
 	u.mutex.Lock()
 	defer u.mutex.Unlock()
diff --git a/pkg/http/handler/timeout_test.go b/pkg/http/handler/timeout_test.go
index 248e986b2..6a3c40ddf 100644
--- a/pkg/http/handler/timeout_test.go
+++ b/pkg/http/handler/timeout_test.go
@@ -29,7 +29,7 @@ func TestTimeoutWriterAllowsForAdditionalWrites(t *testing.T) {
 	recorder := httptest.NewRecorder()
 	handler := &timeoutWriter{w: recorder}
 	handler.WriteHeader(http.StatusOK)
-	handler.TimeoutAndWriteError("error")
+	handler.timeoutAndWriteError("error")
 	if _, err := io.WriteString(handler, "test"); err != nil {
 		t.Fatalf("handler.Write() = %v, want no error", err)
 	}
@@ -45,7 +45,7 @@ func TestTimeoutWriterAllowsForAdditionalWrites(t *testing.T) {
 func TestTimeoutWriterDoesntFlushAfterTimeout(t *testing.T) {
 	recorder := httptest.NewRecorder()
 	handler := &timeoutWriter{w: recorder}
-	handler.TimeoutAndWriteError("error")
+	handler.timeoutAndWriteError("error")
 	handler.Flush()
 
 	if got, want := recorder.Flushed, false; got != want {
@@ -66,16 +66,14 @@ func TestTimeoutWriterFlushesAfterTimeout(t *testing.T) {
 func TestTimeoutWriterErrorsWriteAfterTimeout(t *testing.T) {
 	recorder := httptest.NewRecorder()
 	handler := &timeoutWriter{w: recorder}
-	handler.TimeoutAndWriteError("error")
+	handler.timeoutAndWriteError("error")
 	if _, err := handler.Write([]byte("hello")); err != http.ErrHandlerTimeout {
 		t.Errorf("ErrHandlerTimeout got %v, want: %s", err, http.ErrHandlerTimeout)
 	}
 }
 
 func TestTimeToFirstByteTimeoutHandler(t *testing.T) {
-	const (
-		longTimeout = 10 * time.Second
-	)
+	const longTimeout = 10 * time.Second
 
 	longTimeoutFunc := func(*http.Request) time.Duration {
 		return longTimeout
diff --git a/pkg/network/stats_test.go b/pkg/network/stats_test.go
index a850bd189..b24be1726 100644
--- a/pkg/network/stats_test.go
+++ b/pkg/network/stats_test.go
@@ -192,11 +192,8 @@ func BenchmarkRequestStatsDirect(b *testing.B) {
 
 	go func() {
 		ticker := time.NewTicker(10 * time.Millisecond)
-		for {
-			select {
-			case <-ticker.C:
-				stats.Report(time.Now())
-			}
+		for range ticker.C {
+			stats.Report(time.Now())
 		}
 	}()
 
diff --git a/test/conformance/api/v1/revision_timeout_test.go b/test/conformance/api/v1/revision_timeout_test.go
index 22a834013..0c8a7a2eb 100644
--- a/test/conformance/api/v1/revision_timeout_test.go
+++ b/test/conformance/api/v1/revision_timeout_test.go
@@ -26,9 +26,10 @@ import (
 	"time"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	pkgTest "knative.dev/pkg/test"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
-	revisionresourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
+	resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
 	v1test "knative.dev/serving/test/v1"
@@ -59,8 +60,8 @@ func sendRequest(t *testing.T, clients *test.Clients, endpoint *url.URL,
 	}()
 	u, _ := url.Parse(endpoint.String())
 	q := u.Query()
-	q.Set("initialTimeout", fmt.Sprintf("%d", initialSleep.Milliseconds()))
-	q.Set("timeout", fmt.Sprintf("%d", sleep.Milliseconds()))
+	q.Set("initialTimeout", fmt.Sprint(initialSleep.Milliseconds()))
+	q.Set("timeout", fmt.Sprint(sleep.Milliseconds()))
 	u.RawQuery = q.Encode()
 	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
 	if err != nil {
@@ -87,23 +88,20 @@ func TestRevisionTimeout(t *testing.T) {
 		name           string
 		shouldScaleTo0 bool
 		timeoutSeconds int64
+		initialSleep   time.Duration
+		sleep          time.Duration
 		expectedStatus int
-		initialSleep   int
-		sleep          int
 	}{{
 		name:           "when scaling up from 0 and does not exceed timeout seconds",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          0,
 	}, {
 		name:           "when scaling up from 0 and it writes first byte before timeout",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
+		sleep:          15 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          15,
 	}, {
 		name:           "when scaling up from 0 and it does exceed timeout seconds",
 		shouldScaleTo0: true,
@@ -112,21 +110,19 @@ func TestRevisionTimeout(t *testing.T) {
 	}, {
 		name:           "when pods already exist, and it does not exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   2 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   2,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it does exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   12 * time.Second,
 		expectedStatus: http.StatusGatewayTimeout,
-		initialSleep:   12,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it writes first byte before timeout",
 		timeoutSeconds: 10,
 		expectedStatus: http.StatusOK,
+		sleep:          15 * time.Second,
 		initialSleep:   0,
-		sleep:          15,
 	}}
 
 	for _, tc := range testCases {
@@ -166,7 +162,7 @@ func TestRevisionTimeout(t *testing.T) {
 				t.Fatalf("Unable to fetch URLs from service: %#v", service.Status)
 			}
 
-			serviceURL := url.URL(*service.Status.URL)
+			serviceURL := service.Status.URL.URL()
 
 			if tc.shouldScaleTo0 {
 				t.Log("Waiting to scale down to 0")
@@ -175,25 +171,25 @@ func TestRevisionTimeout(t *testing.T) {
 					t.Fatalf("Error fetching Service %s: %v", names.Service, err)
 				}
 
-				if err := e2e.WaitForScaleToZero(t, revisionresourcenames.Deployment(revision), clients); err != nil {
+				if err := e2e.WaitForScaleToZero(t, resourcenames.Deployment(revision), clients); err != nil {
 					t.Fatal("Could not scale to zero:", err)
 				}
 			} else {
-				t.Log("Probing to force at least one pod", serviceURL.String())
+				t.Log("Probing to force at least one pod", serviceURL)
 				if _, err := pkgTest.WaitForEndpointState(
 					clients.KubeClient,
 					t.Logf,
-					&serviceURL,
+					serviceURL,
 					v1test.RetryingRouteInconsistency(pkgTest.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout)),
 					"WaitForSuccessfulResponse",
 					test.ServingFlags.ResolvableDomain,
 					test.AddRootCAtoTransport(t.Logf, clients, test.ServingFlags.Https)); err != nil {
-					t.Fatalf("Error probing %s: %v", &serviceURL, err)
+					t.Fatalf("Error probing %s: %v", serviceURL, err)
 				}
 			}
 
-			if err := sendRequest(t, clients, &serviceURL, time.Duration(tc.initialSleep)*time.Second, time.Duration(tc.sleep)*time.Second, tc.expectedStatus); err != nil {
-				t.Errorf("Failed request with intialSleep %ds, sleep %ds, with revision timeout %ds and expecting status %v: %v",
+			if err := sendRequest(t, clients, serviceURL, tc.initialSleep, tc.sleep, tc.expectedStatus); err != nil {
+				t.Errorf("Failed request with intialSleep %v, sleep %v, with revision timeout %ds and expecting status %v: %v",
 					tc.initialSleep, tc.sleep, tc.timeoutSeconds, tc.expectedStatus, err)
 			}
 		})
diff --git a/test/conformance/api/v1alpha1/revision_timeout_test.go b/test/conformance/api/v1alpha1/revision_timeout_test.go
index 65763f079..906aa3efc 100644
--- a/test/conformance/api/v1alpha1/revision_timeout_test.go
+++ b/test/conformance/api/v1alpha1/revision_timeout_test.go
@@ -28,7 +28,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	pkgTest "knative.dev/pkg/test"
 	"knative.dev/serving/pkg/apis/serving/v1alpha1"
-	revisionresourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
+	resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
 	v1a1test "knative.dev/serving/test/v1alpha1"
@@ -59,8 +59,8 @@ func sendRequest(t *testing.T, clients *test.Clients, endpoint *url.URL,
 	}()
 	u, _ := url.Parse(endpoint.String())
 	q := u.Query()
-	q.Set("initialTimeout", fmt.Sprintf("%d", initialSleep.Milliseconds()))
-	q.Set("timeout", fmt.Sprintf("%d", sleep.Milliseconds()))
+	q.Set("initialTimeout", fmt.Sprint(initialSleep.Milliseconds()))
+	q.Set("timeout", fmt.Sprint(sleep.Milliseconds()))
 	u.RawQuery = q.Encode()
 	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
 	if err != nil {
@@ -87,23 +87,20 @@ func TestRevisionTimeout(t *testing.T) {
 		name           string
 		shouldScaleTo0 bool
 		timeoutSeconds int64
+		initialSleep   time.Duration
+		sleep          time.Duration
 		expectedStatus int
-		initialSleep   int
-		sleep          int
 	}{{
 		name:           "when scaling up from 0 and does not exceed timeout seconds",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          0,
 	}, {
 		name:           "when scaling up from 0 and it writes first byte before timeout",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
+		sleep:          15 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          15,
 	}, {
 		name:           "when scaling up from 0 and it does exceed timeout seconds",
 		shouldScaleTo0: true,
@@ -112,21 +109,18 @@ func TestRevisionTimeout(t *testing.T) {
 	}, {
 		name:           "when pods already exist, and it does not exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   2 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   2,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it does exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   12 * time.Second,
 		expectedStatus: http.StatusGatewayTimeout,
-		initialSleep:   12,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it writes first byte before timeout",
 		timeoutSeconds: 10,
+		sleep:          15 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          15,
 	}}
 
 	for _, tc := range testCases {
@@ -166,7 +160,7 @@ func TestRevisionTimeout(t *testing.T) {
 				t.Fatalf("Unable to fetch URLs from service: %#v", service.Status)
 			}
 
-			serviceURL := url.URL(*service.Status.URL)
+			serviceURL := service.Status.URL.URL()
 
 			if tc.shouldScaleTo0 {
 				t.Log("Waiting to scale down to 0")
@@ -175,25 +169,25 @@ func TestRevisionTimeout(t *testing.T) {
 					t.Fatalf("Error fetching Service %s: %v", names.Service, err)
 				}
 
-				if err := e2e.WaitForScaleToZero(t, revisionresourcenames.Deployment(revision), clients); err != nil {
+				if err := e2e.WaitForScaleToZero(t, resourcenames.Deployment(revision), clients); err != nil {
 					t.Fatal("Could not scale to zero:", err)
 				}
 			} else {
-				t.Log("Probing to force at least one pod", serviceURL.String())
+				t.Log("Probing to force at least one pod", serviceURL)
 				if _, err := pkgTest.WaitForEndpointState(
 					clients.KubeClient,
 					t.Logf,
-					&serviceURL,
+					serviceURL,
 					v1a1test.RetryingRouteInconsistency(pkgTest.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout)),
 					"WaitForSuccessfulResponse",
 					test.ServingFlags.ResolvableDomain,
 					test.AddRootCAtoTransport(t.Logf, clients, test.ServingFlags.Https)); err != nil {
-					t.Fatalf("Error probing %s: %v", &serviceURL, err)
+					t.Fatalf("Error probing %s: %v", serviceURL, err)
 				}
 			}
 
-			if err := sendRequest(t, clients, &serviceURL, time.Duration(tc.initialSleep)*time.Second, time.Duration(tc.sleep)*time.Second, tc.expectedStatus); err != nil {
-				t.Errorf("Failed request with intialSleep %ds, sleep %ds, with revision timeout %ds and expecting status %v: %v",
+			if err := sendRequest(t, clients, serviceURL, tc.initialSleep, tc.sleep, tc.expectedStatus); err != nil {
+				t.Errorf("Failed request with intialSleep %v, sleep %v, with revision timeout %ds and expecting status %v: %v",
 					tc.initialSleep, tc.sleep, tc.timeoutSeconds, tc.expectedStatus, err)
 			}
 		})
diff --git a/test/conformance/api/v1beta1/revision_timeout_test.go b/test/conformance/api/v1beta1/revision_timeout_test.go
index 2b1900fd0..cbffab13c 100644
--- a/test/conformance/api/v1beta1/revision_timeout_test.go
+++ b/test/conformance/api/v1beta1/revision_timeout_test.go
@@ -28,7 +28,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	pkgTest "knative.dev/pkg/test"
 	"knative.dev/serving/pkg/apis/serving/v1beta1"
-	revisionresourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
+	resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
 	v1b1test "knative.dev/serving/test/v1beta1"
@@ -87,23 +87,20 @@ func TestRevisionTimeout(t *testing.T) {
 		name           string
 		shouldScaleTo0 bool
 		timeoutSeconds int64
+		initialSleep   time.Duration
+		sleep          time.Duration
 		expectedStatus int
-		initialSleep   int
-		sleep          int
 	}{{
 		name:           "when scaling up from 0 and does not exceed timeout seconds",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          0,
 	}, {
 		name:           "when scaling up from 0 and it writes first byte before timeout",
 		shouldScaleTo0: true,
 		timeoutSeconds: 10,
+		sleep:          15 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          15,
 	}, {
 		name:           "when scaling up from 0 and it does exceed timeout seconds",
 		shouldScaleTo0: true,
@@ -112,21 +109,18 @@ func TestRevisionTimeout(t *testing.T) {
 	}, {
 		name:           "when pods already exist, and it does not exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   2 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   2,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it does exceed timeout seconds",
 		timeoutSeconds: 10,
+		initialSleep:   12 * time.Second,
 		expectedStatus: http.StatusGatewayTimeout,
-		initialSleep:   12,
-		sleep:          0,
 	}, {
 		name:           "when pods already exist, and it writes first byte before timeout",
 		timeoutSeconds: 10,
+		sleep:          15 * time.Second,
 		expectedStatus: http.StatusOK,
-		initialSleep:   0,
-		sleep:          15,
 	}}
 
 	for _, tc := range testCases {
@@ -166,7 +160,7 @@ func TestRevisionTimeout(t *testing.T) {
 				t.Fatalf("Unable to fetch URLs from service: %#v", service.Status)
 			}
 
-			serviceURL := url.URL(*service.Status.URL)
+			serviceURL := service.Status.URL.URL()
 
 			if tc.shouldScaleTo0 {
 				t.Log("Waiting to scale down to 0")
@@ -175,25 +169,25 @@ func TestRevisionTimeout(t *testing.T) {
 					t.Fatalf("Error fetching Service %s: %v", names.Service, err)
 				}
 
-				if err := e2e.WaitForScaleToZero(t, revisionresourcenames.Deployment(revision), clients); err != nil {
+				if err := e2e.WaitForScaleToZero(t, resourcenames.Deployment(revision), clients); err != nil {
 					t.Fatal("Could not scale to zero:", err)
 				}
 			} else {
-				t.Log("Probing to force at least one pod", serviceURL.String())
+				t.Log("Probing to force at least one pod", serviceURL)
 				if _, err := pkgTest.WaitForEndpointState(
 					clients.KubeClient,
 					t.Logf,
-					&serviceURL,
+					serviceURL,
 					v1b1test.RetryingRouteInconsistency(pkgTest.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout)),
 					"WaitForSuccessfulResponse",
 					test.ServingFlags.ResolvableDomain,
 					test.AddRootCAtoTransport(t.Logf, clients, test.ServingFlags.Https)); err != nil {
-					t.Fatalf("Error probing %s: %v", &serviceURL, err)
+					t.Fatalf("Error probing %s: %v", serviceURL, err)
 				}
 			}
 
-			if err := sendRequest(t, clients, &serviceURL, time.Duration(tc.initialSleep)*time.Second, time.Duration(tc.sleep)*time.Second, tc.expectedStatus); err != nil {
-				t.Errorf("Failed request with intialSleep %ds, sleep %ds, with revision timeout %ds and expecting status %v: %v",
+			if err := sendRequest(t, clients, serviceURL, tc.initialSleep, tc.sleep, tc.expectedStatus); err != nil {
+				t.Errorf("Failed request with intialSleep %v, sleep %v, with revision timeout %ds and expecting status %v: %v",
 					tc.initialSleep, tc.sleep, tc.timeoutSeconds, tc.expectedStatus, err)
 			}
 		})
diff --git a/test/conformance/certificate/README.md b/test/conformance/certificate/README.md
new file mode 100644
index 000000000..063616e41
--- /dev/null
+++ b/test/conformance/certificate/README.md
@@ -0,0 +1,32 @@
+# Certificate Conformance Testing
+
+## Adding a test
+
+Tests need to be exported and accessible downstream so they should be placed in
+non-test files (ie. sometest.go). Additionally, invoke your test in the default
+`RunConformance` function in [`run.go`](./http01/run.go). This function is the
+entry point by which tests are executed.
+
+This approach aims to reduce the changes required when tests are added &
+removed.
+
+## Running the tests downstream
+
+To run all the conformance tests in your own repo we encourage adopting the
+[`RunConformance`](./http01/run.go) function to run all your tests.
+
+To do so would look something like:
+
+```go
+package conformance
+
+import (
+	"testing"
+	"knative.dev/serving/test/conformance/certificate/http01"
+)
+
+func TestYourHTTP01ProviderConformance(t *testing.T) {
+	http01.RunConformance(t)
+}
+
+```
diff --git a/test/conformance/ingress/README.md b/test/conformance/ingress/README.md
index b7573088e..5867ea8dc 100644
--- a/test/conformance/ingress/README.md
+++ b/test/conformance/ingress/README.md
@@ -1,4 +1,4 @@
-# Test
+# Ingress Conformance Testing
 
 This directory contains Ingress conformance tests for Knative Ingress resource.
 
@@ -60,6 +60,16 @@ To run the script for all end to end test images:
 $SERVING_ROOT/test/upload-test-images.sh
 ```
 
+## Adding a test
+
+Tests need to be exported and accessible downstream so they should be placed in
+non-test files (ie. sometest.go). Additionally, invoke your test in the default
+`RunConformance` function in [`run.go`](./run.go). This function is the entry
+point by which tests are executed.
+
+This approach aims to reduce the changes required when tests are added &
+removed.
+
 ## Running the tests
 
 ```bash
@@ -75,3 +85,24 @@ go test -v -tags=e2e -count=1 test/conformance/ingress \
     --ingressClass="$INGRESS_CLASS" \
     --ingressendpoint=$INGRESSENDPOINT
 ```
+
+## Running the tests downstream
+
+To run all the conformance tests in your own repo we encourage adopting the
+[`RunConformance`](./run.go) function to run all your tests.
+
+To do so would look something like:
+
+```go
+package conformance
+
+import (
+	"testing"
+	"knative.dev/serving/test/conformance/ingress"
+)
+
+func TestYourIngressConformance(t *testing.T) {
+	ingress.RunConformance(t)
+}
+
+```
diff --git a/test/e2e/autoscale.go b/test/e2e/autoscale.go
index 5d098198b..4b4f1b6bb 100644
--- a/test/e2e/autoscale.go
+++ b/test/e2e/autoscale.go
@@ -302,11 +302,12 @@ func numberOfReadyPods(ctx *testContext) (float64, error) {
 func checkPodScale(ctx *testContext, targetPods, minPods, maxPods float64, duration time.Duration) error {
 	// Short-circuit traffic generation once we exit from the check logic.
 	done := time.After(duration)
-	timer := time.Tick(2 * time.Second)
+	ticker := time.NewTicker(2 * time.Second)
+	defer ticker.Stop()
 
 	for {
 		select {
-		case <-timer:
+		case <-ticker.C:
 			// Each 2 second, check that the number of pods is at least `minPods`. `minPods` is increasing
 			// to verify that the number of pods doesn't go down while we are scaling up.
 			got, err := numberOfReadyPods(ctx)
diff --git a/third_party/kourier-latest/kourier.yaml b/third_party/kourier-latest/kourier.yaml
index fa1115bc9..a160db6cf 100644
--- a/third_party/kourier-latest/kourier.yaml
+++ b/third_party/kourier-latest/kourier.yaml
@@ -166,7 +166,7 @@ spec:
         app: 3scale-kourier-control
     spec:
       containers:
-      - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:50c4153c679f98e89a4d302c9ed4710d88cb8e342df7c6174beaa442f28b14a4
+      - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:d19e8a480309208bf47346ef2e25309bc22261d65b42ea7fb399991c579d83fa
         imagePullPolicy: Always
         name: kourier-control
         env:
diff --git a/vendor/knative.dev/pkg/configmap/testing/configmap.go b/vendor/knative.dev/pkg/configmap/testing/configmap.go
index d50dfe610..bd61285bf 100644
--- a/vendor/knative.dev/pkg/configmap/testing/configmap.go
+++ b/vendor/knative.dev/pkg/configmap/testing/configmap.go
@@ -75,7 +75,7 @@ func ConfigMapsFromTestFile(t *testing.T, name string, allowed ...string) (*core
 	}
 	// With the length and membership checks, we know that the keyspace matches.
 
-	exampleBody := orig.Data[configmap.ExampleKey]
+	exampleBody, hasExampleBody := orig.Data[configmap.ExampleKey]
 	// Check that exampleBody does not have lines that end in a trailing space,
 	for i, line := range strings.Split(exampleBody, "\n") {
 		if strings.TrimRightFunc(line, unicode.IsSpace) != line {
@@ -83,6 +83,15 @@ func ConfigMapsFromTestFile(t *testing.T, name string, allowed ...string) (*core
 		}
 	}
 
+	// Check that the hashed exampleBody matches the assigned label, if present.
+	gotChecksum, hasExampleChecksumLabel := orig.Labels[configmap.ExampleChecksumLabel]
+	if hasExampleBody && hasExampleChecksumLabel {
+		wantChecksum := fmt.Sprint(configmap.Checksum(exampleBody))
+		if gotChecksum != wantChecksum {
+			t.Errorf("example checksum label = %s, want %s", gotChecksum, wantChecksum)
+		}
+	}
+
 	// Parse exampleBody into exemplar.Data
 	exemplar := orig.DeepCopy()
 	if err := yaml.Unmarshal([]byte(exampleBody), &exemplar.Data); err != nil {
diff --git a/vendor/knative.dev/pkg/test/gcs/client.go b/vendor/knative.dev/pkg/test/gcs/client.go
new file mode 100644
index 000000000..a78318abe
--- /dev/null
+++ b/vendor/knative.dev/pkg/test/gcs/client.go
@@ -0,0 +1,51 @@
+/*
+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 gcs
+
+import (
+	"context"
+
+	"cloud.google.com/go/storage"
+)
+
+type Client interface {
+	// NewStorageBucket creates a new bucket in GCS with uniform access policy
+	NewStorageBucket(ctx context.Context, bkt, project string) error
+	// DeleteStorageBucket removes all children objects, force if not empty
+	DeleteStorageBucket(ctx context.Context, bkt string, force bool) error
+	// Exists check if an object exists under a bucket, assuming bucket exists
+	Exists(ctx context.Context, bkt, objPath string) bool
+	// ListChildrenFiles recursively lists all children files
+	ListChildrenFiles(ctx context.Context, bkt, dirPath string) ([]string, error)
+	// ListDirectChildren lists direct children paths (incl. files and dir)
+	ListDirectChildren(ctx context.Context, bkt, dirPath string) ([]string, error)
+	// AttrObject returns the object attributes
+	AttrObject(ctx context.Context, bkt, objPath string) (*storage.ObjectAttrs, error)
+	// CopyObject copies objects from one location to another, assuming both src and dst
+	// buckets both exist
+	CopyObject(ctx context.Context, srcBkt, srcObjPath, dstBkt, dstObjPath string) error
+	// ReadObject reads a GCS object and returns then contents in []byte
+	ReadObject(ctx context.Context, bkt, objPath string) ([]byte, error)
+	// WriteObject writes []byte content to a GCS object
+	WriteObject(ctx context.Context, bkt, objPath string, content []byte) (int, error)
+	// DeleteObject deletes an object
+	DeleteObject(ctx context.Context, bkt, objPath string) error
+	// Download downloads GCS object to a local file, assuming bucket exists
+	Download(ctx context.Context, bktName, objPath, filePath string) error
+	// Upload uploads a local file to a GCS object, assuming bucket exists
+	Upload(ctx context.Context, bktName, objPath, filePath string) error
+}
diff --git a/vendor/knative.dev/pkg/test/gcs/gcs.go b/vendor/knative.dev/pkg/test/gcs/gcs.go
index 05208c194..fc3cc3e21 100644
--- a/vendor/knative.dev/pkg/test/gcs/gcs.go
+++ b/vendor/knative.dev/pkg/test/gcs/gcs.go
@@ -14,17 +14,14 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-// gcs.go defines functions to use GCS
-
 package gcs
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
-	"log"
-	"net/url"
 	"os"
 	"path"
 	"strings"
@@ -34,54 +31,146 @@ import (
 	"google.golang.org/api/option"
 )
 
-var client *storage.Client
+type GCSClient struct {
+	*storage.Client
+}
 
-// Authenticate explicitly sets up authentication for the rest of run
-func Authenticate(ctx context.Context, serviceAccount string) error {
-	var err error
-	client, err = storage.NewClient(ctx, option.WithCredentialsFile(serviceAccount))
-	return err
+// NewClient creates new GCS client with given service account
+func NewClient(ctx context.Context, serviceAccount string) (*GCSClient, error) {
+	client, err := storage.NewClient(ctx, option.WithCredentialsFile(serviceAccount))
+	if err != nil {
+		return nil, err
+	}
+	return &GCSClient{Client: client}, nil
+}
+
+// NewStorageBucket creates a new bucket in GCS with uniform access policy
+func (g *GCSClient) NewStorageBucket(ctx context.Context, bucketName, project string) error {
+	if project == "" {
+		return errors.New("a project must be provided")
+	}
+
+	if bucketName == "" {
+		return errors.New("a bucket name must be provided")
+	}
+
+	bucket := g.Bucket(bucketName)
+
+	// For now, this creates a bucket with uniform policy across its objects to make ACL
+	// and permission management simple instead of object-level granularity that we currently
+	// do not use anyway.
+	bucketAttr := &storage.BucketAttrs{
+		BucketPolicyOnly: storage.BucketPolicyOnly{
+			Enabled: true,
+		},
+	}
+
+	return bucket.Create(ctx, project, bucketAttr)
+}
+
+// DeleteStorageBucket removes all children objects and then deletes the bucket
+func (g *GCSClient) DeleteStorageBucket(ctx context.Context, bucketName string, force bool) error {
+	children, err := g.ListChildrenFiles(ctx, bucketName, "")
+	if err != nil {
+		return err
+	}
+
+	if len(children) == 0 && !force {
+		return fmt.Errorf("bucket %s not empty, please use force=true", bucketName)
+	}
+
+	for _, child := range children {
+		if err := g.DeleteObject(ctx, bucketName, child); err != nil {
+			return err
+		}
+	}
+	return g.Bucket(bucketName).Delete(ctx)
+}
+
+// get objects iterator under given storagePath and bucketName, use exclusionFilter to eliminate some files.
+func (g *GCSClient) getObjectsIter(ctx context.Context, bucketName, storagePath, exclusionFilter string) *storage.ObjectIterator {
+	return g.Bucket(bucketName).Objects(ctx, &storage.Query{
+		Prefix:    storagePath,
+		Delimiter: exclusionFilter,
+	})
 }
 
-// Exists checks if path exist under gcs bucket,
-// this path can either be a directory or a file.
-func Exists(ctx context.Context, bucketName, storagePath string) bool {
+// Exists check if an object exists under a bucket, assuming bucket exists
+func (g *GCSClient) Exists(ctx context.Context, bucketName, objPath string) bool {
 	// Check if this is a file
-	handle := createStorageObject(bucketName, storagePath)
-	if _, err := handle.Attrs(ctx); err == nil {
+	objHandle := g.Bucket(bucketName).Object(objPath)
+	if _, err := objHandle.Attrs(ctx); err == nil {
 		return true
 	}
+
 	// Check if this is a directory,
-	// gcs directory paths are virtual paths, they automatically got deleted if there is no child file
-	_, err := getObjectsIter(ctx, bucketName, strings.TrimRight(storagePath, " /")+"/", "").Next()
+	// gcs directory paths are virtual paths, they automatically get deleted if there is no child file
+	_, err := g.getObjectsIter(ctx, bucketName, strings.TrimRight(objPath, " /")+"/", "").Next()
 	return err == nil
 }
 
+// list child under storagePath, use exclusionFilter for skipping some files.
+// This function gets all child files recursively under given storagePath,
+// then filter out filenames containing given exclusionFilter.
+// If exclusionFilter is empty string, returns all files but not directories,
+// if exclusionFilter is "/", returns all direct children, including both files and directories.
+// see https://godoc.org/cloud.google.com/go/storage#Query
+func (g *GCSClient) list(ctx context.Context, bucketName, storagePath, exclusionFilter string) ([]string, error) {
+	objsAttrs, err := g.getObjectsAttrs(ctx, bucketName, storagePath, exclusionFilter)
+	if err != nil {
+		return nil, err
+	}
+	var filePaths []string
+	for _, attrs := range objsAttrs {
+		filePaths = append(filePaths, path.Join(attrs.Prefix, attrs.Name))
+	}
+	return filePaths, nil
+}
+
+// Query items under given gcs storagePath, use exclusionFilter to eliminate some files.
+func (g *GCSClient) getObjectsAttrs(ctx context.Context, bucketName, storagePath,
+	exclusionFilter string) ([]*storage.ObjectAttrs, error) {
+	var allAttrs []*storage.ObjectAttrs
+	it := g.getObjectsIter(ctx, bucketName, storagePath, exclusionFilter)
+
+	for {
+		attrs, err := it.Next()
+		if err == iterator.Done {
+			break
+		}
+		if err != nil {
+			return nil, fmt.Errorf("error iterating: %v", err)
+		}
+		allAttrs = append(allAttrs, attrs)
+	}
+	return allAttrs, nil
+}
+
 // ListChildrenFiles recursively lists all children files.
-func ListChildrenFiles(ctx context.Context, bucketName, storagePath string) []string {
-	return list(ctx, bucketName, strings.TrimRight(storagePath, " /")+"/", "")
+func (g *GCSClient) ListChildrenFiles(ctx context.Context, bucketName, dirPath string) ([]string, error) {
+	return g.list(ctx, bucketName, strings.TrimRight(dirPath, " /")+"/", "")
 }
 
 // ListDirectChildren lists direct children paths (including files and directories).
-func ListDirectChildren(ctx context.Context, bucketName, storagePath string) []string {
+func (g *GCSClient) ListDirectChildren(ctx context.Context, bucketName, dirPath string) ([]string, error) {
 	// If there are 2 directories named "foo" and "foobar",
 	// then given storagePath "foo" will get files both under "foo" and "foobar".
 	// Add trailling slash to storagePath, so that only gets children under given directory.
-	return list(ctx, bucketName, strings.TrimRight(storagePath, " /")+"/", "/")
+	return g.list(ctx, bucketName, strings.TrimRight(dirPath, " /")+"/", "/")
 }
 
-// Copy file from within gcs
-func Copy(ctx context.Context, srcBucketName, srcPath, dstBucketName, dstPath string) error {
-	src := createStorageObject(srcBucketName, srcPath)
-	dst := createStorageObject(dstBucketName, dstPath)
+// CopyObject copies objects from one location to another. Assumes both source and destination buckets exist.
+func (g *GCSClient) CopyObject(ctx context.Context, srcBucketName, srcPath, dstBucketName, dstPath string) error {
+	src := g.Bucket(srcBucketName).Object(srcPath)
+	dst := g.Bucket(dstBucketName).Object(dstPath)
 
 	_, err := dst.CopierFrom(src).Run(ctx)
 	return err
 }
 
-// Download file from gcs
-func Download(ctx context.Context, bucketName, srcPath, dstPath string) error {
-	handle := createStorageObject(bucketName, srcPath)
+// Download gcs object to a file
+func (g *GCSClient) Download(ctx context.Context, bucketName, objPath, dstPath string) error {
+	handle := g.Bucket(bucketName).Object(objPath)
 	if _, err := handle.Attrs(ctx); err != nil {
 		return err
 	}
@@ -99,22 +188,28 @@ func Download(ctx context.Context, bucketName, srcPath, dstPath string) error {
 	return err
 }
 
-// Upload file to gcs
-func Upload(ctx context.Context, bucketName, dstPath, srcPath string) error {
+// Upload file to gcs object
+func (g *GCSClient) Upload(ctx context.Context, bucketName, objPath, srcPath string) error {
 	src, err := os.Open(srcPath)
 	if err != nil {
 		return err
 	}
-	dst := createStorageObject(bucketName, dstPath).NewWriter(ctx)
+	dst := g.Bucket(bucketName).Object(objPath).NewWriter(ctx)
 	defer dst.Close()
 	_, err = io.Copy(dst, src)
 	return err
 }
 
-// Read reads the specified file
-func Read(ctx context.Context, bucketName, filePath string) ([]byte, error) {
+// AttrObject returns the object attributes
+func (g *GCSClient) AttrObject(ctx context.Context, bucketName, objPath string) (*storage.ObjectAttrs, error) {
+	objHandle := g.Bucket(bucketName).Object(objPath)
+	return objHandle.Attrs(ctx)
+}
+
+// ReadObject reads the content of a gcs object
+func (g *GCSClient) ReadObject(ctx context.Context, bucketName, objPath string) ([]byte, error) {
 	var contents []byte
-	f, err := NewReader(ctx, bucketName, filePath)
+	f, err := g.NewReader(ctx, bucketName, objPath)
 	if err != nil {
 		return contents, err
 	}
@@ -122,103 +217,43 @@ func Read(ctx context.Context, bucketName, filePath string) ([]byte, error) {
 	return ioutil.ReadAll(f)
 }
 
-// ReadURL reads from a gsUrl and return a log structure
-func ReadURL(ctx context.Context, gcsURL string) ([]byte, error) {
-	bucket, obj, err := linkToBucketAndObject(gcsURL)
-	if err != nil {
-		return nil, err
-	}
-
-	return Read(ctx, bucket, obj)
-}
-
 // NewReader creates a new Reader of a gcs file.
 // Important: caller must call Close on the returned Reader when done reading
-func NewReader(ctx context.Context, bucketName, filePath string) (*storage.Reader, error) {
-	o := createStorageObject(bucketName, filePath)
+func (g *GCSClient) NewReader(ctx context.Context, bucketName, objPath string) (*storage.Reader, error) {
+	o := g.Bucket(bucketName).Object(objPath)
 	if _, err := o.Attrs(ctx); err != nil {
 		return nil, err
 	}
 	return o.NewReader(ctx)
 }
 
-// BuildLogPath returns the build log path from the test result gcsURL
-func BuildLogPath(gcsURL string) (string, error) {
-	u, err := url.Parse(gcsURL)
-	if err != nil {
-		return gcsURL, err
-	}
-	u.Path = path.Join(u.Path, "build-log.txt")
-	return u.String(), nil
-}
-
-// GetConsoleURL returns the gcs link renderable directly from a browser
-func GetConsoleURL(gcsURL string) (string, error) {
-	u, err := url.Parse(gcsURL)
-	if err != nil {
-		return gcsURL, err
-	}
-	u.Path = path.Join("storage/browser", u.Host, u.Path)
-	u.Scheme = "https"
-	u.Host = "console.cloud.google.com"
-	return u.String(), nil
+// DeleteObject deletes an object
+func (g *GCSClient) DeleteObject(ctx context.Context, bucketName, objPath string) error {
+	objHandle := g.Bucket(bucketName).Object(objPath)
+	return objHandle.Delete(ctx)
 }
 
-// create storage object handle, this step doesn't access internet
-func createStorageObject(bucketName, filePath string) *storage.ObjectHandle {
-	return client.Bucket(bucketName).Object(filePath)
-}
-
-// Query items under given gcs storagePath, use exclusionFilter to eliminate some files.
-func getObjectsAttrs(ctx context.Context, bucketName, storagePath, exclusionFilter string) []*storage.ObjectAttrs {
-	var allAttrs []*storage.ObjectAttrs
-	it := getObjectsIter(ctx, bucketName, storagePath, exclusionFilter)
-
-	for {
-		attrs, err := it.Next()
-		if err == iterator.Done {
-			break
+// WriteObject writes the content to a gcs object
+func (g *GCSClient) WriteObject(ctx context.Context, bucketName, objPath string,
+	content []byte) (n int, err error) {
+	objWriter := g.Bucket(bucketName).Object(objPath).NewWriter(ctx)
+	defer func() {
+		cerr := objWriter.Close()
+		if err == nil {
+			err = cerr
 		}
-		if err != nil {
-			log.Fatalf("Error iterating: %v", err)
-		}
-		allAttrs = append(allAttrs, attrs)
-	}
-	return allAttrs
-}
+	}()
 
-// list child under storagePath, use exclusionFilter for skipping some files.
-// This function gets all child files recursively under given storagePath,
-// then filter out filenames containing giving exclusionFilter.
-// If exclusionFilter is empty string, returns all files but not directories,
-// if exclusionFilter is "/", returns all direct children, including both files and directories.
-// see https://godoc.org/cloud.google.com/go/storage#Query
-func list(ctx context.Context, bucketName, storagePath, exclusionFilter string) []string {
-	objsAttrs := getObjectsAttrs(ctx, bucketName, storagePath, exclusionFilter)
-	filePaths := make([]string, 0, len(objsAttrs))
-	for _, attrs := range objsAttrs {
-		filePaths = append(filePaths, path.Join(attrs.Prefix, attrs.Name))
-	}
-	return filePaths
+	n, err = objWriter.Write(content)
+	return
 }
 
-// get objects iterator under given storagePath and bucketName, use exclusionFilter to eliminate some files.
-func getObjectsIter(ctx context.Context, bucketName, storagePath, exclusionFilter string) *storage.ObjectIterator {
-	return client.Bucket(bucketName).Objects(ctx, &storage.Query{
-		Prefix:    storagePath,
-		Delimiter: exclusionFilter,
-	})
-}
-
-// get the bucket and object from the gsURL
-func linkToBucketAndObject(gsURL string) (string, string, error) {
-	var bucket, obj string
-	gsURL = strings.Replace(gsURL, "gs://", "", 1)
-
-	sIdx := strings.IndexByte(gsURL, '/')
-	if sIdx == -1 || sIdx+1 >= len(gsURL) {
-		return bucket, obj, fmt.Errorf("the gsUrl (%s) cannot be converted to bucket/object", gsURL)
+// ReadURL reads from a gsUrl and return a log structure
+func (g *GCSClient) ReadURL(ctx context.Context, gcsURL string) ([]byte, error) {
+	bucket, obj, err := linkToBucketAndObject(gcsURL)
+	if err != nil {
+		return nil, err
 	}
 
-	return gsURL[:sIdx], gsURL[sIdx+1:], nil
+	return g.ReadObject(ctx, bucket, obj)
 }
diff --git a/vendor/knative.dev/pkg/test/gcs/helpers.go b/vendor/knative.dev/pkg/test/gcs/helpers.go
new file mode 100644
index 000000000..150999ed8
--- /dev/null
+++ b/vendor/knative.dev/pkg/test/gcs/helpers.go
@@ -0,0 +1,58 @@
+/*
+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 gcs
+
+import (
+	"fmt"
+	"net/url"
+	"path"
+	"strings"
+)
+
+// get the bucket and object from the gsURL
+func linkToBucketAndObject(gsURL string) (string, string, error) {
+	gsURL = strings.Replace(gsURL, "gs://", "", 1)
+
+	sIdx := strings.IndexByte(gsURL, '/')
+	if sIdx == -1 || sIdx+1 >= len(gsURL) {
+		return "", "", fmt.Errorf("the gsUrl (%q) cannot be converted to bucket/object", gsURL)
+	}
+
+	return gsURL[:sIdx], gsURL[sIdx+1:], nil
+}
+
+// BuildLogPath returns the build log path from the test result gcsURL
+func BuildLogPath(gcsURL string) (string, error) {
+	u, err := url.Parse(gcsURL)
+	if err != nil {
+		return gcsURL, err
+	}
+	u.Path = path.Join(u.Path, "build-log.txt")
+	return u.String(), nil
+}
+
+// GetConsoleURL returns the gcs link renderable directly from a browser
+func GetConsoleURL(gcsURL string) (string, error) {
+	u, err := url.Parse(gcsURL)
+	if err != nil {
+		return gcsURL, err
+	}
+	u.Path = path.Join("storage/browser", u.Host, u.Path)
+	u.Scheme = "https"
+	u.Host = "console.cloud.google.com"
+	return u.String(), nil
+}
diff --git a/vendor/knative.dev/pkg/test/junit/junit.go b/vendor/knative.dev/pkg/test/junit/junit.go
index 2e53da618..bc69067be 100644
--- a/vendor/knative.dev/pkg/test/junit/junit.go
+++ b/vendor/knative.dev/pkg/test/junit/junit.go
@@ -21,6 +21,8 @@ package junit
 import (
 	"encoding/xml"
 	"fmt"
+	"io/ioutil"
+	"log"
 )
 
 // TestStatusEnum is a enum for test result status
@@ -144,3 +146,24 @@ func UnMarshal(buf []byte) (*TestSuites, error) {
 	}
 	return &testSuites, nil
 }
+
+// CreateXMLErrorMsg outputs a junit testsuite, testname and error message to the destination path
+// in XML format
+func CreateXMLErrorMsg(testSuite, testName, errMsg, dest string) {
+	suites := TestSuites{}
+	suite := TestSuite{Name: testSuite}
+	var errP *string
+	if errMsg != "" {
+		errP = &errMsg
+	}
+	suite.AddTestCase(TestCase{
+		Name:    testName,
+		Failure: errP,
+	})
+	suites.AddTestSuite(&suite)
+	contents, err := suites.ToBytes("", "")
+	if err != nil {
+		log.Fatal(err)
+	}
+	ioutil.WriteFile(dest, contents, 0644)
+}
diff --git a/vendor/knative.dev/pkg/test/prow/prow.go b/vendor/knative.dev/pkg/test/prow/prow.go
index 2af8a0095..c5304ce27 100644
--- a/vendor/knative.dev/pkg/test/prow/prow.go
+++ b/vendor/knative.dev/pkg/test/prow/prow.go
@@ -59,8 +59,8 @@ const (
 
 // defined here so that it can be mocked for unit testing
 var logFatalf = log.Fatalf
-
 var ctx = context.Background()
+var client *gcs.GCSClient
 
 // Job struct represents a job directory in gcs.
 // gcs job StoragePath will be derived from Type if it's defined,
@@ -128,7 +128,9 @@ func GetLocalArtifactsDir() string {
 
 // Initialize wraps gcs authentication, have to be invoked before any other functions
 func Initialize(serviceAccount string) error {
-	return gcs.Authenticate(ctx, serviceAccount)
+	var err error
+	client, err = gcs.NewClient(ctx, serviceAccount)
+	return err
 }
 
 // NewJob creates new job struct
@@ -158,13 +160,13 @@ func NewJob(jobName, jobType, orgName, repoName string, pullID int) *Job {
 
 // PathExists checks if the storage path of a job exists in gcs or not
 func (j *Job) PathExists() bool {
-	return gcs.Exists(ctx, BucketName, j.StoragePath)
+	return client.Exists(ctx, BucketName, j.StoragePath)
 }
 
 // GetLatestBuildNumber gets the latest build number for job
 func (j *Job) GetLatestBuildNumber() (int, error) {
 	logFilePath := path.Join(j.StoragePath, Latest)
-	contents, err := gcs.Read(ctx, BucketName, logFilePath)
+	contents, err := client.ReadObject(ctx, BucketName, logFilePath)
 	if err != nil {
 		return 0, err
 	}
@@ -223,7 +225,7 @@ func (j *Job) GetBuilds() []Build {
 // for job, keeps the ones that can be parsed as integer
 func (j *Job) GetBuildIDs() []int {
 	var buildIDs []int
-	gcsBuildPaths := gcs.ListDirectChildren(ctx, j.Bucket, j.StoragePath)
+	gcsBuildPaths, _ := client.ListDirectChildren(ctx, j.Bucket, j.StoragePath)
 	for _, gcsBuildPath := range gcsBuildPaths {
 		if buildID, err := getBuildIDFromBuildPath(gcsBuildPath); err == nil {
 			buildIDs = append(buildIDs, buildID)
@@ -256,12 +258,12 @@ func (j *Job) GetLatestBuilds(count int) []Build {
 
 // IsStarted check if build has started by looking at "started.json" file
 func (b *Build) IsStarted() bool {
-	return gcs.Exists(ctx, BucketName, path.Join(b.StoragePath, StartedJSON))
+	return client.Exists(ctx, BucketName, path.Join(b.StoragePath, StartedJSON))
 }
 
 // IsFinished check if build has finished by looking at "finished.json" file
 func (b *Build) IsFinished() bool {
-	return gcs.Exists(ctx, BucketName, path.Join(b.StoragePath, FinishedJSON))
+	return client.Exists(ctx, BucketName, path.Join(b.StoragePath, FinishedJSON))
 }
 
 // GetStartTime gets started timestamp of a build,
@@ -286,7 +288,8 @@ func (b *Build) GetFinishTime() (int64, error) {
 
 // GetArtifacts gets gcs path for all artifacts of current build
 func (b *Build) GetArtifacts() []string {
-	return gcs.ListChildrenFiles(ctx, BucketName, b.GetArtifactsDir())
+	artifacts, _ := client.ListChildrenFiles(ctx, BucketName, b.GetArtifactsDir())
+	return artifacts
 }
 
 // GetArtifactsDir gets gcs path for artifacts of current build
@@ -302,7 +305,7 @@ func (b *Build) GetBuildLogPath() string {
 // ReadFile reads given file of current build,
 // relPath is the file path relative to build directory
 func (b *Build) ReadFile(relPath string) ([]byte, error) {
-	return gcs.Read(ctx, BucketName, path.Join(b.StoragePath, relPath))
+	return client.ReadObject(ctx, BucketName, path.Join(b.StoragePath, relPath))
 }
 
 // ParseLog parses the build log and returns the lines where the checkLog func does not return an empty slice,
@@ -310,7 +313,7 @@ func (b *Build) ReadFile(relPath string) ([]byte, error) {
 func (b *Build) ParseLog(checkLog func(s []string) *string) ([]string, error) {
 	var logs []string
 
-	f, err := gcs.NewReader(ctx, b.Bucket, b.GetBuildLogPath())
+	f, err := client.NewReader(ctx, b.Bucket, b.GetBuildLogPath())
 	if err != nil {
 		return logs, err
 	}
@@ -333,7 +336,7 @@ func getBuildIDFromBuildPath(buildPath string) (int, error) {
 // unmarshalJSONFile reads a file from gcs, parses it with xml and write to v.
 // v must be an arbitrary struct, slice, or string.
 func unmarshalJSONFile(storagePath string, v interface{}) error {
-	contents, err := gcs.Read(ctx, BucketName, storagePath)
+	contents, err := client.ReadObject(ctx, BucketName, storagePath)
 	if err != nil {
 		return err
 	}