import unittest2 class Test__httplib2_debug_level(unittest2.TestCase): def _getTargetClass(self): from gcloud.streaming.http_wrapper import _httplib2_debug_level return _httplib2_debug_level def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_wo_loggable_body_wo_http(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT request = _Request() LEVEL = 1 _httplib2 = _Dummy(debuglevel=0) with _Monkey(MUT, httplib2=_httplib2): with self._makeOne(request, LEVEL): self.assertEqual(_httplib2.debuglevel, 0) def test_w_loggable_body_wo_http(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT request = _Request(loggable_body=object()) LEVEL = 1 _httplib2 = _Dummy(debuglevel=0) with _Monkey(MUT, httplib2=_httplib2): with self._makeOne(request, LEVEL): self.assertEqual(_httplib2.debuglevel, LEVEL) self.assertEqual(_httplib2.debuglevel, 0) def test_w_loggable_body_w_http(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT class _Connection(object): debuglevel = 0 def set_debuglevel(self, value): self.debuglevel = value request = _Request(loggable_body=object()) LEVEL = 1 _httplib2 = _Dummy(debuglevel=0) update_me = _Connection() skip_me = _Connection() connections = {'update:me': update_me, 'skip_me': skip_me} _http = _Dummy(connections=connections) with _Monkey(MUT, httplib2=_httplib2): with self._makeOne(request, LEVEL, _http): self.assertEqual(_httplib2.debuglevel, LEVEL) self.assertEqual(update_me.debuglevel, LEVEL) self.assertEqual(skip_me.debuglevel, 0) self.assertEqual(_httplib2.debuglevel, 0) self.assertEqual(update_me.debuglevel, 0) self.assertEqual(skip_me.debuglevel, 0) class Test_Request(unittest2.TestCase): def _getTargetClass(self): from gcloud.streaming.http_wrapper import Request return Request def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor_defaults(self): request = self._makeOne() self.assertEqual(request.url, '') self.assertEqual(request.http_method, 'GET') self.assertEqual(request.headers, {'content-length': '0'}) self.assertEqual(request.body, '') self.assertEqual(request.loggable_body, None) def test_loggable_body_setter_w_body_None(self): from gcloud.streaming.exceptions import RequestError request = self._makeOne(body=None) with self.assertRaises(RequestError): request.loggable_body = 'abc' def test_body_setter_w_None(self): request = self._makeOne() request.loggable_body = 'abc' request.body = None self.assertEqual(request.headers, {}) self.assertEqual(request.body, None) self.assertEqual(request.loggable_body, 'abc') def test_body_setter_w_non_string(self): request = self._makeOne() request.loggable_body = 'abc' request.body = body = _Dummy(length=123) self.assertEqual(request.headers, {'content-length': '123'}) self.assertTrue(request.body is body) self.assertEqual(request.loggable_body, '') class Test_Response(unittest2.TestCase): def _getTargetClass(self): from gcloud.streaming.http_wrapper import Response return Response def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' info = {'status': '200'} response = self._makeOne(info, CONTENT, URL) self.assertEqual(len(response), len(CONTENT)) self.assertEqual(response.status_code, 200) self.assertEqual(response.retry_after, None) self.assertFalse(response.is_redirect) def test_length_w_content_encoding_w_content_range(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' RANGE = 'bytes 0-122/5678' info = { 'status': '200', 'content-length': len(CONTENT), 'content-encoding': 'testing', 'content-range': RANGE, } response = self._makeOne(info, CONTENT, URL) self.assertEqual(len(response), 123) def test_length_w_content_encoding_wo_content_range(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' info = { 'status': '200', 'content-length': len(CONTENT), 'content-encoding': 'testing', } response = self._makeOne(info, CONTENT, URL) self.assertEqual(len(response), len(CONTENT)) def test_length_w_content_length_w_content_range(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' RANGE = 'bytes 0-12/5678' info = { 'status': '200', 'content-length': len(CONTENT) * 2, 'content-range': RANGE, } response = self._makeOne(info, CONTENT, URL) self.assertEqual(len(response), len(CONTENT) * 2) def test_length_wo_content_length_w_content_range(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' RANGE = 'bytes 0-122/5678' info = { 'status': '200', 'content-range': RANGE, } response = self._makeOne(info, CONTENT, URL) self.assertEqual(len(response), 123) def test_retry_after_w_header(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' info = { 'status': '200', 'retry-after': '123', } response = self._makeOne(info, CONTENT, URL) self.assertEqual(response.retry_after, 123) def test_is_redirect_w_code_wo_location(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' info = { 'status': '301', } response = self._makeOne(info, CONTENT, URL) self.assertFalse(response.is_redirect) def test_is_redirect_w_code_w_location(self): CONTENT = 'CONTENT' URL = 'http://example.com/api' info = { 'status': '301', 'location': 'http://example.com/other', } response = self._makeOne(info, CONTENT, URL) self.assertTrue(response.is_redirect) class Test__check_response(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import _check_response return _check_response(*args, **kw) def test_w_none(self): from gcloud.streaming.exceptions import RequestError with self.assertRaises(RequestError): self._callFUT(None) def test_w_TOO_MANY_REQUESTS(self): from gcloud.streaming.exceptions import BadStatusCodeError from gcloud.streaming.http_wrapper import TOO_MANY_REQUESTS with self.assertRaises(BadStatusCodeError): self._callFUT(_Response(TOO_MANY_REQUESTS)) def test_w_50x(self): from gcloud.streaming.exceptions import BadStatusCodeError with self.assertRaises(BadStatusCodeError): self._callFUT(_Response(500)) with self.assertRaises(BadStatusCodeError): self._callFUT(_Response(503)) def test_w_retry_after(self): from gcloud.streaming.exceptions import RetryAfterError with self.assertRaises(RetryAfterError): self._callFUT(_Response(200, 20)) def test_pass(self): self._callFUT(_Response(200)) class Test__reset_http_connections(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import _reset_http_connections return _reset_http_connections(*args, **kw) def test_wo_connections(self): http = object() self._callFUT(http) def test_w_connections(self): connections = {'delete:me': object(), 'skip_me': object()} http = _Dummy(connections=connections) self._callFUT(http) self.assertFalse('delete:me' in connections) self.assertTrue('skip_me' in connections) class Test___make_api_request_no_retry(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import _make_api_request_no_retry return _make_api_request_no_retry(*args, **kw) def _verify_requested(self, http, request, redirections=5, connection_type=None): self.assertEqual(len(http._requested), 1) url, kw = http._requested[0] self.assertEqual(url, request.url) self.assertEqual(kw['method'], request.http_method) self.assertEqual(kw['body'], request.body) self.assertEqual(kw['headers'], request.headers) self.assertEqual(kw['redirections'], redirections) self.assertEqual(kw['connection_type'], connection_type) def test_defaults_wo_connections(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT INFO = {'status': '200'} CONTENT = 'CONTENT' _http = _Http((INFO, CONTENT)) _httplib2 = _Dummy(debuglevel=1) _request = _Request() _checked = [] with _Monkey(MUT, httplib2=_httplib2): response = self._callFUT(_http, _request, check_response_func=_checked.append) self.assertTrue(isinstance(response, MUT.Response)) self.assertEqual(response.info, INFO) self.assertEqual(response.content, CONTENT) self.assertEqual(response.request_url, _request.url) self.assertEqual(_checked, [response]) self._verify_requested(_http, _request) def test_w_explicit_redirections(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT INFO = {'status': '200'} CONTENT = 'CONTENT' _http = _Http((INFO, CONTENT)) _httplib2 = _Dummy(debuglevel=1) _request = _Request() _checked = [] with _Monkey(MUT, httplib2=_httplib2): response = self._callFUT(_http, _request, redirections=10, check_response_func=_checked.append) self.assertTrue(isinstance(response, MUT.Response)) self.assertEqual(response.info, INFO) self.assertEqual(response.content, CONTENT) self.assertEqual(response.request_url, _request.url) self.assertEqual(_checked, [response]) self._verify_requested(_http, _request, redirections=10) def test_w_http_connections_miss(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT INFO = {'status': '200'} CONTENT = 'CONTENT' CONN_TYPE = object() _http = _Http((INFO, CONTENT)) _http.connections = {'https': CONN_TYPE} _httplib2 = _Dummy(debuglevel=1) _request = _Request() _checked = [] with _Monkey(MUT, httplib2=_httplib2): response = self._callFUT(_http, _request, check_response_func=_checked.append) self.assertTrue(isinstance(response, MUT.Response)) self.assertEqual(response.info, INFO) self.assertEqual(response.content, CONTENT) self.assertEqual(response.request_url, _request.url) self.assertEqual(_checked, [response]) self._verify_requested(_http, _request) def test_w_http_connections_hit(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT INFO = {'status': '200'} CONTENT = 'CONTENT' CONN_TYPE = object() _http = _Http((INFO, CONTENT)) _http.connections = {'http': CONN_TYPE} _httplib2 = _Dummy(debuglevel=1) _request = _Request() _checked = [] with _Monkey(MUT, httplib2=_httplib2): response = self._callFUT(_http, _request, check_response_func=_checked.append) self.assertTrue(isinstance(response, MUT.Response)) self.assertEqual(response.info, INFO) self.assertEqual(response.content, CONTENT) self.assertEqual(response.request_url, _request.url) self.assertEqual(_checked, [response]) self._verify_requested(_http, _request, connection_type=CONN_TYPE) def test_w_request_returning_None(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT from gcloud.streaming.exceptions import RequestError INFO = None CONTENT = None CONN_TYPE = object() _http = _Http((INFO, CONTENT)) _http.connections = {'http': CONN_TYPE} _httplib2 = _Dummy(debuglevel=1) _request = _Request() with _Monkey(MUT, httplib2=_httplib2): with self.assertRaises(RequestError): self._callFUT(_http, _request) self._verify_requested(_http, _request, connection_type=CONN_TYPE) class Test_make_api_request(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import make_api_request return make_api_request(*args, **kw) def test_wo_exception(self): HTTP, REQUEST, RESPONSE = object(), object(), object() _created, _checked = [], [] def _wo_exception(*args, **kw): _created.append((args, kw)) return RESPONSE response = self._callFUT(HTTP, REQUEST, wo_retry_func=_wo_exception, check_response_func=_checked.append) self.assertTrue(response is RESPONSE) expected_kw = { 'redirections': 5, 'check_response_func': _checked.append, } self.assertEqual(_created, [((HTTP, REQUEST), expected_kw)]) self.assertEqual(_checked, []) # not called by '_wo_exception' def test_w_exceptions_lt_max_retries(self): from gcloud.streaming.exceptions import RetryAfterError HTTP, RESPONSE = object(), object() REQUEST = _Request() WAIT = 10, _created, _checked = [], [] _counter = [None] * 4 def _wo_exception(*args, **kw): _created.append((args, kw)) if _counter: _counter.pop() raise RetryAfterError(RESPONSE, '', REQUEST.url, 0.1) return RESPONSE response = self._callFUT(HTTP, REQUEST, retries=5, max_retry_wait=WAIT, wo_retry_func=_wo_exception, check_response_func=_checked.append) self.assertTrue(response is RESPONSE) self.assertEqual(len(_created), 5) expected_kw = { 'redirections': 5, 'check_response_func': _checked.append, } for attempt in _created: self.assertEqual(attempt, ((HTTP, REQUEST), expected_kw)) self.assertEqual(_checked, []) # not called by '_wo_exception' def test_w_exceptions_gt_max_retries(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT HTTP = object() REQUEST = _Request() WAIT = 10, _created, _checked = [], [] def _wo_exception(*args, **kw): _created.append((args, kw)) raise ValueError('Retryable') with _Monkey(MUT, calculate_wait_for_retry=lambda *ignored: 0.1): with self.assertRaises(ValueError): self._callFUT(HTTP, REQUEST, retries=3, max_retry_wait=WAIT, wo_retry_func=_wo_exception, check_response_func=_checked.append) self.assertEqual(len(_created), 3) expected_kw = { 'redirections': 5, 'check_response_func': _checked.append, } for attempt in _created: self.assertEqual(attempt, ((HTTP, REQUEST), expected_kw)) self.assertEqual(_checked, []) # not called by '_wo_exception' class Test__register_http_factory(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import _register_http_factory return _register_http_factory(*args, **kw) def test_it(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT _factories = [] FACTORY = object() with _Monkey(MUT, _HTTP_FACTORIES=_factories): self._callFUT(FACTORY) self.assertEqual(_factories, [FACTORY]) class Test_get_http(unittest2.TestCase): def _callFUT(self, *args, **kw): from gcloud.streaming.http_wrapper import get_http return get_http(*args, **kw) def test_wo_registered_factories(self): from httplib2 import Http from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT _factories = [] with _Monkey(MUT, _HTTP_FACTORIES=_factories): http = self._callFUT() self.assertTrue(isinstance(http, Http)) def test_w_registered_factories(self): from gcloud._testing import _Monkey from gcloud.streaming import http_wrapper as MUT FOUND = object() _misses = [] def _miss(**kw): _misses.append(kw) return None _hits = [] def _hit(**kw): _hits.append(kw) return FOUND _factories = [_miss, _hit] with _Monkey(MUT, _HTTP_FACTORIES=_factories): http = self._callFUT(foo='bar') self.assertTrue(http is FOUND) self.assertEqual(_misses, [{'foo': 'bar'}]) self.assertEqual(_hits, [{'foo': 'bar'}]) class _Dummy(object): def __init__(self, **kw): self.__dict__.update(kw) class _Request(object): __slots__ = ('url', 'http_method', 'body', 'headers', 'loggable_body',) URL = 'http://example.com/api' def __init__(self, url=URL, http_method='GET', body='', loggable_body=None): self.url = url self.http_method = http_method self.body = body self.headers = {} self.loggable_body = loggable_body class _Response(object): content = '' request_url = _Request.URL def __init__(self, status_code, retry_after=None): self.info = {'status': status_code} self.status_code = status_code self.retry_after = retry_after class _Http(object): def __init__(self, *responses): self._responses = responses self._requested = [] def request(self, url, **kw): self._requested.append((url, kw)) response, self._responses = self._responses[0], self._responses[1:] return response