http-backend: catch errors from HTTP calls that are not raising exceptions, but

return non 200 exception codes.
This commit is contained in:
Marcin Kuzminski 2017-02-07 16:16:42 +01:00
parent 3d3f2db34a
commit f8f9bdc988
3 changed files with 67 additions and 18 deletions

View file

@ -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()

View file

@ -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')

View file

@ -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()