http-backend: catch errors from HTTP calls that are not raising exceptions, but
return non 200 exception codes.
This commit is contained in:
parent
3d3f2db34a
commit
f8f9bdc988
3 changed files with 67 additions and 18 deletions
|
|
@ -216,7 +216,9 @@ class CurlSession(object):
|
|||
curl.setopt(curl.WRITEDATA, response_buffer)
|
||||
curl.perform()
|
||||
|
||||
return CurlResponse(response_buffer)
|
||||
status_code = curl.getinfo(pycurl.HTTP_CODE)
|
||||
|
||||
return CurlResponse(response_buffer, status_code)
|
||||
|
||||
|
||||
class CurlResponse(object):
|
||||
|
|
@ -228,13 +230,18 @@ class CurlResponse(object):
|
|||
`requests` as a drop in replacement for benchmarking purposes.
|
||||
"""
|
||||
|
||||
def __init__(self, response_buffer):
|
||||
def __init__(self, response_buffer, status_code):
|
||||
self._response_buffer = response_buffer
|
||||
self._status_code = status_code
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return self._response_buffer.getvalue()
|
||||
|
||||
@property
|
||||
def status_code(self):
|
||||
return self._status_code
|
||||
|
||||
|
||||
def _create_http_rpc_session():
|
||||
session = CurlSession()
|
||||
|
|
|
|||
|
|
@ -196,10 +196,15 @@ def _remote_call(url, payload, exceptions_map, session):
|
|||
except pycurl.error as e:
|
||||
raise exceptions.HttpVCSCommunicationError(e)
|
||||
|
||||
if response.status_code >= 400:
|
||||
log.error('Call to %s returned non 200 HTTP code: %s',
|
||||
url, response.status_code)
|
||||
raise exceptions.HttpVCSCommunicationError(repr(response.content))
|
||||
|
||||
try:
|
||||
response = msgpack.unpackb(response.content)
|
||||
except Exception:
|
||||
log.exception('Failed to decode repsponse %r', response.content)
|
||||
log.exception('Failed to decode response %r', response.content)
|
||||
raise
|
||||
|
||||
error = response.get('error')
|
||||
|
|
|
|||
|
|
@ -25,20 +25,7 @@ import msgpack
|
|||
import pytest
|
||||
|
||||
from rhodecode.lib import vcs
|
||||
from rhodecode.lib.vcs import client_http
|
||||
|
||||
|
||||
def test_uses_persistent_http_connections(caplog, vcsbackend_hg):
|
||||
repo = vcsbackend_hg.repo
|
||||
remote_call = repo._remote.branches
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
for x in range(5):
|
||||
remote_call(normal=True, closed=False)
|
||||
|
||||
new_connections = [
|
||||
r for r in caplog.record_tuples if is_new_connection(*r)]
|
||||
assert len(new_connections) <= 1
|
||||
from rhodecode.lib.vcs import client_http, exceptions
|
||||
|
||||
|
||||
def is_new_connection(logger, level, message):
|
||||
|
|
@ -53,7 +40,24 @@ def stub_session():
|
|||
Stub of `requests.Session()`.
|
||||
"""
|
||||
session = mock.Mock()
|
||||
session.post().content = msgpack.packb({})
|
||||
post = session.post()
|
||||
post.content = msgpack.packb({})
|
||||
post.status_code = 200
|
||||
|
||||
session.reset_mock()
|
||||
return session
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def stub_fail_session():
|
||||
"""
|
||||
Stub of `requests.Session()`.
|
||||
"""
|
||||
session = mock.Mock()
|
||||
post = session.post()
|
||||
post.content = msgpack.packb({'error': '500'})
|
||||
post.status_code = 500
|
||||
|
||||
session.reset_mock()
|
||||
return session
|
||||
|
||||
|
|
@ -68,6 +72,29 @@ def stub_session_factory(stub_session):
|
|||
return session_factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def stub_session_failing_factory(stub_fail_session):
|
||||
"""
|
||||
Stub of `rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory`.
|
||||
"""
|
||||
session_factory = mock.Mock()
|
||||
session_factory.return_value = stub_fail_session
|
||||
return session_factory
|
||||
|
||||
|
||||
def test_uses_persistent_http_connections(caplog, vcsbackend_hg):
|
||||
repo = vcsbackend_hg.repo
|
||||
remote_call = repo._remote.branches
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
for x in range(5):
|
||||
remote_call(normal=True, closed=False)
|
||||
|
||||
new_connections = [
|
||||
r for r in caplog.record_tuples if is_new_connection(*r)]
|
||||
assert len(new_connections) <= 1
|
||||
|
||||
|
||||
def test_repo_maker_uses_session_for_classmethods(stub_session_factory):
|
||||
repo_maker = client_http.RepoMaker(
|
||||
'server_and_port', 'endpoint', 'test_dummy_scm', stub_session_factory)
|
||||
|
|
@ -94,3 +121,13 @@ def test_connect_passes_in_the_same_session(
|
|||
session_factory.return_value = stub_session
|
||||
|
||||
vcs.connect_http('server_and_port')
|
||||
|
||||
|
||||
def test_repo_maker_uses_session_that_throws_error(
|
||||
stub_session_failing_factory, config):
|
||||
repo_maker = client_http.RepoMaker(
|
||||
'server_and_port', 'endpoint', 'test_dummy_scm', stub_session_failing_factory)
|
||||
repo = repo_maker('stub_path', config)
|
||||
|
||||
with pytest.raises(exceptions.HttpVCSCommunicationError):
|
||||
repo.example_call()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue