test(bigquery): add testing for retry predicate (#3902)
Adds a minor nil check to the retry predicate, and adds a table test for the predicate function.
Release-As: bigquery/v1.17.0
diff --git a/bigquery/bigquery.go b/bigquery/bigquery.go
index 025c5e3..1beb248 100644
--- a/bigquery/bigquery.go
+++ b/bigquery/bigquery.go
@@ -166,6 +166,9 @@
// retryable; these are returned by systems between the client and the BigQuery
// service.
func retryableError(err error) bool {
+ if err == nil {
+ return false
+ }
// Special case due to http2: https://github.com/googleapis/google-cloud-go/issues/1793
// Due to Go's default being higher for streams-per-connection than is accepted by the
// BQ backend, it's possible to get streams refused immediately after a connection is
diff --git a/bigquery/bigquery_test.go b/bigquery/bigquery_test.go
new file mode 100644
index 0000000..c5a05aa
--- /dev/null
+++ b/bigquery/bigquery_test.go
@@ -0,0 +1,93 @@
+// Copyright 2021 Google LLC
+//
+// 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 bigquery
+
+import (
+ "errors"
+ "net/http"
+ "testing"
+
+ "google.golang.org/api/googleapi"
+)
+
+func TestRetryableErrors(t *testing.T) {
+ for _, tc := range []struct {
+ description string
+ in error
+ want bool
+ }{
+ {
+ "nil error",
+ nil,
+ false,
+ },
+ {
+ "http stream closed",
+ errors.New("http2: stream closed"),
+ true,
+ },
+ {
+ "unavailable",
+ &googleapi.Error{
+ Code: http.StatusServiceUnavailable,
+ Message: "foo",
+ },
+ true,
+ },
+ {
+ // not retried per https://google.aip.dev/194
+ "internal error",
+ &googleapi.Error{
+ Code: http.StatusInternalServerError,
+ },
+ false,
+ },
+ {
+ "internal w/backend reason",
+ &googleapi.Error{
+ Code: http.StatusServiceUnavailable,
+ Message: "foo",
+ Errors: []googleapi.ErrorItem{
+ {Reason: "backendError", Message: "foo"},
+ },
+ },
+ true,
+ },
+ {
+ "internal w/rateLimitExceeded reason",
+ &googleapi.Error{
+ Code: http.StatusServiceUnavailable,
+ Message: "foo",
+ Errors: []googleapi.ErrorItem{
+ {Reason: "rateLimitExceeded", Message: "foo"},
+ },
+ },
+ true,
+ },
+ {
+ "bad gateway error",
+ &googleapi.Error{
+ Code: http.StatusBadGateway,
+ Message: "foo",
+ },
+ true,
+ },
+ } {
+ got := retryableError(tc.in)
+ if got != tc.want {
+ t.Errorf("case (%s) mismatch: got %t want %t", tc.description, got, tc.want)
+ }
+ }
+}