1# 2# Copyright 2015 Google Inc. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16"""Tests for http_wrapper.""" 17import socket 18import unittest 19 20import httplib2 21from six.moves import http_client 22 23from mock import patch 24 25from apitools.base.py import exceptions 26from apitools.base.py import http_wrapper 27 28# pylint: disable=ungrouped-imports 29try: 30 from oauth2client.client import HttpAccessTokenRefreshError 31 from oauth2client.client import AccessTokenRefreshError 32 _TOKEN_REFRESH_STATUS_AVAILABLE = True 33except ImportError: 34 from oauth2client.client import AccessTokenRefreshError 35 _TOKEN_REFRESH_STATUS_AVAILABLE = False 36 37 38class _MockHttpRequest(object): 39 40 url = None 41 42 43class _MockHttpResponse(object): 44 45 def __init__(self, status_code): 46 self.response = {'status': status_code} 47 48 49class RaisesExceptionOnLen(object): 50 51 """Supports length property but raises if __len__ is used.""" 52 53 def __len__(self): 54 raise Exception('len() called unnecessarily') 55 56 def length(self): 57 return 1 58 59 60class HttpWrapperTest(unittest.TestCase): 61 62 def testRequestBodyUsesLengthProperty(self): 63 http_wrapper.Request(body=RaisesExceptionOnLen()) 64 65 def testRequestBodyWithLen(self): 66 http_wrapper.Request(body='burrito') 67 68 @unittest.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE, 69 'oauth2client<1.5 lacks HttpAccessTokenRefreshError.') 70 def testExceptionHandlerHttpAccessTokenError(self): 71 exception_arg = HttpAccessTokenRefreshError(status=503) 72 retry_args = http_wrapper.ExceptionRetryArgs( 73 http={'connections': {}}, http_request=_MockHttpRequest(), 74 exc=exception_arg, num_retries=0, max_retry_wait=0, 75 total_wait_sec=0) 76 77 # Disable time.sleep for this handler as it is called with 78 # a minimum value of 1 second. 79 with patch('time.sleep', return_value=None): 80 http_wrapper.HandleExceptionsAndRebuildHttpConnections( 81 retry_args) 82 83 @unittest.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE, 84 'oauth2client<1.5 lacks HttpAccessTokenRefreshError.') 85 def testExceptionHandlerHttpAccessTokenErrorRaises(self): 86 exception_arg = HttpAccessTokenRefreshError(status=200) 87 retry_args = http_wrapper.ExceptionRetryArgs( 88 http={'connections': {}}, http_request=_MockHttpRequest(), 89 exc=exception_arg, num_retries=0, max_retry_wait=0, 90 total_wait_sec=0) 91 92 # Disable time.sleep for this handler as it is called with 93 # a minimum value of 1 second. 94 with self.assertRaises(HttpAccessTokenRefreshError): 95 with patch('time.sleep', return_value=None): 96 http_wrapper.HandleExceptionsAndRebuildHttpConnections( 97 retry_args) 98 99 def testExceptionHandlerAccessTokenErrorRaises(self): 100 exception_arg = AccessTokenRefreshError() 101 retry_args = http_wrapper.ExceptionRetryArgs( 102 http={'connections': {}}, http_request=_MockHttpRequest(), 103 exc=exception_arg, num_retries=0, max_retry_wait=0, 104 total_wait_sec=0) 105 106 # Disable time.sleep for this handler as it is called with 107 # a minimum value of 1 second. 108 with self.assertRaises(AccessTokenRefreshError): 109 with patch('time.sleep', return_value=None): 110 http_wrapper.HandleExceptionsAndRebuildHttpConnections( 111 retry_args) 112 113 def testDefaultExceptionHandler(self): 114 """Ensures exception handles swallows (retries)""" 115 mock_http_content = 'content'.encode('utf8') 116 for exception_arg in ( 117 http_client.BadStatusLine('line'), 118 http_client.IncompleteRead('partial'), 119 http_client.ResponseNotReady(), 120 socket.error(), 121 socket.gaierror(), 122 httplib2.ServerNotFoundError(), 123 ValueError(), 124 exceptions.RequestError(), 125 exceptions.BadStatusCodeError( 126 {'status': 503}, mock_http_content, 'url'), 127 exceptions.RetryAfterError( 128 {'status': 429}, mock_http_content, 'url', 0)): 129 130 retry_args = http_wrapper.ExceptionRetryArgs( 131 http={'connections': {}}, http_request=_MockHttpRequest(), 132 exc=exception_arg, num_retries=0, max_retry_wait=0, 133 total_wait_sec=0) 134 135 # Disable time.sleep for this handler as it is called with 136 # a minimum value of 1 second. 137 with patch('time.sleep', return_value=None): 138 http_wrapper.HandleExceptionsAndRebuildHttpConnections( 139 retry_args) 140