...

Source file src/cloud.google.com/go/bigquery/bigquery_test.go

Documentation: cloud.google.com/go/bigquery

     1  // Copyright 2021 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bigquery
    16  
    17  import (
    18  	"errors"
    19  	"io"
    20  	"net/http"
    21  	"net/url"
    22  	"testing"
    23  
    24  	"golang.org/x/xerrors"
    25  	"google.golang.org/api/googleapi"
    26  )
    27  
    28  func TestRetryableErrors(t *testing.T) {
    29  	testCases := []struct {
    30  		description        string
    31  		in                 error
    32  		useJobRetryReasons bool
    33  		wantRetry          bool
    34  	}{
    35  		{
    36  			description: "nil error",
    37  			in:          nil,
    38  			wantRetry:   false,
    39  		},
    40  		{
    41  			description: "http stream closed",
    42  			in:          errors.New("http2: stream closed"),
    43  			wantRetry:   true,
    44  		},
    45  		{
    46  			description: "io ErrUnexpectedEOF",
    47  			in:          io.ErrUnexpectedEOF,
    48  			wantRetry:   true,
    49  		},
    50  		{
    51  			description: "unavailable",
    52  			in: &googleapi.Error{
    53  				Code:    http.StatusServiceUnavailable,
    54  				Message: "foo",
    55  			},
    56  			wantRetry: true,
    57  		},
    58  		{
    59  			description: "url connection error",
    60  			in:          &url.Error{Op: "blah", URL: "blah", Err: errors.New("connection refused")},
    61  			wantRetry:   true,
    62  		},
    63  		{
    64  			description: "url other error",
    65  			in:          &url.Error{Op: "blah", URL: "blah", Err: errors.New("blah")},
    66  			wantRetry:   false,
    67  		},
    68  		{
    69  			description: "wrapped retryable",
    70  			in: xerrors.Errorf("test of wrapped retryable: %w", &googleapi.Error{
    71  				Code:    http.StatusServiceUnavailable,
    72  				Message: "foo",
    73  				Errors: []googleapi.ErrorItem{
    74  					{Reason: "backendError", Message: "foo"},
    75  				},
    76  			}),
    77  			wantRetry: true,
    78  		},
    79  		{
    80  			description: "wrapped non-retryable",
    81  			in:          xerrors.Errorf("test of wrapped retryable: %w", errors.New("blah")),
    82  			wantRetry:   false,
    83  		},
    84  		{
    85  			// not retried per https://google.aip.dev/194
    86  			description: "internal error",
    87  			in: &googleapi.Error{
    88  				Code: http.StatusInternalServerError,
    89  			},
    90  			wantRetry: true,
    91  		},
    92  		{
    93  			description: "internal w/backend reason",
    94  			in: &googleapi.Error{
    95  				Code:    http.StatusServiceUnavailable,
    96  				Message: "foo",
    97  				Errors: []googleapi.ErrorItem{
    98  					{Reason: "backendError", Message: "foo"},
    99  				},
   100  			},
   101  			wantRetry: true,
   102  		},
   103  		{
   104  			description: "internal w/rateLimitExceeded reason",
   105  			in: &googleapi.Error{
   106  				Code:    http.StatusServiceUnavailable,
   107  				Message: "foo",
   108  				Errors: []googleapi.ErrorItem{
   109  					{Reason: "rateLimitExceeded", Message: "foo"},
   110  				},
   111  			},
   112  			wantRetry: true,
   113  		},
   114  		{
   115  			description: "bad gateway error",
   116  			in: &googleapi.Error{
   117  				Code:    http.StatusBadGateway,
   118  				Message: "foo",
   119  			},
   120  			wantRetry: true,
   121  		},
   122  		{
   123  			description: "jobRateLimitExceeded default",
   124  			in: &googleapi.Error{
   125  				Code:    http.StatusOK, // ensure we're testing the reason
   126  				Message: "foo",
   127  				Errors: []googleapi.ErrorItem{
   128  					{Reason: "jobRateLimitExceeded", Message: "foo"},
   129  				},
   130  			},
   131  			wantRetry: false,
   132  		},
   133  		{
   134  			description: "jobRateLimitExceeded job",
   135  			in: &googleapi.Error{
   136  				Code:    http.StatusOK, // ensure we're testing the reason
   137  				Message: "foo",
   138  				Errors: []googleapi.ErrorItem{
   139  					{Reason: "jobRateLimitExceeded", Message: "foo"},
   140  				},
   141  			},
   142  			useJobRetryReasons: true,
   143  			wantRetry:          true,
   144  		},
   145  		{
   146  			description: "structured internal error default",
   147  			in: &googleapi.Error{
   148  				Code:    http.StatusOK, // ensure we're testing the reason
   149  				Message: "foo",
   150  				Errors: []googleapi.ErrorItem{
   151  					{Reason: "internalError", Message: "foo"},
   152  				},
   153  			},
   154  			wantRetry: false,
   155  		},
   156  		{
   157  			description: "structured internal error default",
   158  			in: &googleapi.Error{
   159  				Code:    http.StatusOK, // ensure we're testing the reason
   160  				Message: "foo",
   161  				Errors: []googleapi.ErrorItem{
   162  					{Reason: "internalError", Message: "foo"},
   163  				},
   164  			},
   165  			useJobRetryReasons: true,
   166  			wantRetry:          true,
   167  		},
   168  	}
   169  
   170  	for _, testcase := range testCases {
   171  		tc := testcase
   172  		t.Run(tc.description, func(t *testing.T) {
   173  			t.Parallel()
   174  			reasons := defaultRetryReasons
   175  			if tc.useJobRetryReasons {
   176  				reasons = jobRetryReasons
   177  			}
   178  			got := retryableError(tc.in, reasons)
   179  			if got != tc.wantRetry {
   180  				t.Errorf("case (%s) mismatch:  got %t wantRetry %t", tc.description, got, tc.wantRetry)
   181  			}
   182  		})
   183  	}
   184  }
   185  

View as plain text