示例#1
0
 def test_wait_on_failure_does_not_exceed_60_secs_wait(self, mock_sleep):
     total_attempts = 20
     for attempt in range(1, total_attempts + 1):
         controlflow.wait_on_failure(
             attempt,
             total_attempts,
             'Attempt #%s' % attempt,
             # Suppress messages while we make a lot of attempts.
             error_print_threshold=total_attempts + 1)
         # Wait time may be between 60 and 61 secs, due to rand addition.
         self.assertLessEqual(mock_sleep.call_args[0][0], 61)
示例#2
0
 def test_wait_on_failure_only_prints_after_threshold(self, mock_stderr_write,
                                                      unused_mock_sleep):
   total_attempts = 5
   threshold = 3
   for attempt in range(1, total_attempts + 1):
     controlflow.wait_on_failure(
         attempt,
         total_attempts,
         'Attempt #%s' % attempt,
         error_print_threshold=threshold)
   self.assertEqual(total_attempts - threshold, mock_stderr_write.call_count)
示例#3
0
    def test_wait_on_failure_waits_exponentially(self, mock_sleep):
        controlflow.wait_on_failure(1, 5, 'Backoff attempt #1')
        controlflow.wait_on_failure(2, 5, 'Backoff attempt #2')
        controlflow.wait_on_failure(3, 5, 'Backoff attempt #3')

        sleep_calls = mock_sleep.call_args_list
        self.assertGreaterEqual(sleep_calls[0][0][0], 2**1)
        self.assertGreaterEqual(sleep_calls[1][0][0], 2**2)
        self.assertGreaterEqual(sleep_calls[2][0][0], 2**3)
示例#4
0
def call(service,
         function,
         silent_errors=False,
         soft_errors=False,
         throw_reasons=None,
         retry_reasons=None,
         **kwargs):
    """Executes a single request on a Google service function.

  Args:
    service: A Google service object for the desired API.
    function: String, The name of a service request method to execute.
    silent_errors: Bool, If True, error messages are suppressed when
      encountered.
    soft_errors: Bool, If True, writes non-fatal errors to stderr.
    throw_reasons: A list of Google HTTP error reason strings indicating the
      errors generated by this request should be re-thrown. All other HTTP
      errors are consumed.
    retry_reasons: A list of Google HTTP error reason strings indicating which
      error should be retried, using exponential backoff techniques, when the
      error reason is encountered.
    **kwargs: Additional params to pass to the request method.

  Returns:
    A response object for the corresponding Google API call.
  """
    if throw_reasons is None:
        throw_reasons = []
    if retry_reasons is None:
        retry_reasons = []

    method = getattr(service, function)
    retries = 10
    parameters = dict(
        list(kwargs.items()) + list(GM_Globals[GM_EXTRA_ARGS_DICT].items()))
    for n in range(1, retries + 1):
        try:
            return method(**parameters).execute()
        except googleapiclient.errors.HttpError as e:
            http_status, reason, message = errors.get_gapi_error_detail(
                e,
                soft_errors=soft_errors,
                silent_errors=silent_errors,
                retry_on_http_error=n < 3)
            if http_status == -1:
                # The error detail indicated that we should retry this request
                # We'll refresh credentials and make another pass
                service._http.request.credentials.refresh(
                    transport.create_http())
                continue
            if http_status == 0:
                return None

            is_known_error_reason = reason in [
                r.value for r in errors.ErrorReason
            ]
            if is_known_error_reason and errors.ErrorReason(
                    reason) in throw_reasons:
                if errors.ErrorReason(
                        reason) in errors.ERROR_REASON_TO_EXCEPTION:
                    raise errors.ERROR_REASON_TO_EXCEPTION[errors.ErrorReason(
                        reason)](message)
                raise e
            if (n != retries) and (
                    is_known_error_reason and errors.ErrorReason(reason)
                    in errors.DEFAULT_RETRY_REASONS + retry_reasons):
                controlflow.wait_on_failure(n, retries, reason)
                continue
            if soft_errors:
                display.print_error(
                    f'{http_status}: {message} - {reason}{["", ": Giving up."][n > 1]}'
                )
                return None
            controlflow.system_error_exit(
                int(http_status), f'{http_status}: {message} - {reason}')
        except google.auth.exceptions.RefreshError as e:
            handle_oauth_token_error(
                e, soft_errors
                or errors.ErrorReason.SERVICE_NOT_AVAILABLE in throw_reasons)
            if errors.ErrorReason.SERVICE_NOT_AVAILABLE in throw_reasons:
                raise errors.GapiServiceNotAvailableError(str(e))
            display.print_error(
                f'User {GM_Globals[GM_CURRENT_API_USER]}: {str(e)}')
            return None
        except ValueError as e:
            if hasattr(service._http,
                       'cache') and service._http.cache is not None:
                service._http.cache = None
                continue
            controlflow.system_error_exit(4, str(e))
        except (httplib2.ServerNotFoundError, RuntimeError) as e:
            if n != retries:
                service._http.connections = {}
                controlflow.wait_on_failure(n, retries, str(e))
                continue
            controlflow.system_error_exit(4, str(e))
        except TypeError as e:
            controlflow.system_error_exit(4, str(e))
示例#5
0
 def test_wait_on_failure_prints_errors(self, unused_mock_sleep):
     message = 'An error message to display'
     with patch.object(controlflow.sys.stderr,
                       'write') as mock_stderr_write:
         controlflow.wait_on_failure(1, 5, message, error_print_threshold=0)
     self.assertIn(message, mock_stderr_write.call_args[0][0])
示例#6
0
 def test_wait_on_failure_prints_errors(self, mock_stderr_write,
                                        unused_mock_sleep):
   message = 'An error message to display'
   controlflow.wait_on_failure(1, 5, message, error_print_threshold=0)
   self.assertIn(message, mock_stderr_write.call_args[0][0])