diff --git a/neutronclient/client.py b/neutronclient/client.py index 1afa37096..fefa07b63 100644 --- a/neutronclient/client.py +++ b/neutronclient/client.py @@ -113,7 +113,6 @@ class HTTPClient(httplib2.Http): self.endpoint_url = endpoint_url self.auth_strategy = auth_strategy # httplib2 overrides - self.force_exception_to_status_code = True self.disable_ssl_certificate_validation = insecure def _cs_request(self, *args, **kwargs): @@ -133,7 +132,13 @@ class HTTPClient(httplib2.Http): args = utils.safe_encode_list(args) kargs = utils.safe_encode_dict(kargs) utils.http_log_req(_logger, args, kargs) - resp, body = self.request(*args, **kargs) + try: + resp, body = self.request(*args, **kargs) + except Exception as e: + # Wrap the low-level connection error (socket timeout, redirect + # limit, decompression error, etc) into our custom high-level + # connection exception (it is excepted in the upper layers of code) + raise exceptions.ConnectionFailed(reason=e) utils.http_log_resp(_logger, resp, body) status_code = self.get_status_code(resp) if status_code == 401: diff --git a/tests/unit/test_http.py b/tests/unit/test_http.py new file mode 100644 index 000000000..09182324f --- /dev/null +++ b/tests/unit/test_http.py @@ -0,0 +1,64 @@ +# Copyright (C) 2013 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import httplib2 +import mox +import testtools + +from neutronclient.client import HTTPClient +from neutronclient.common import exceptions +from tests.unit.test_cli20 import MyResp + + +AUTH_TOKEN = 'test_token' +END_URL = 'test_url' +METHOD = 'GET' +URL = 'http://test.test:1234/v2.0/test' + + +class TestHTTPClient(testtools.TestCase): + def setUp(self): + super(TestHTTPClient, self).setUp() + + self.mox = mox.Mox() + self.mox.StubOutWithMock(httplib2.Http, 'request') + self.addCleanup(self.mox.UnsetStubs) + + self.http = HTTPClient(token=AUTH_TOKEN, endpoint_url=END_URL) + + def test_request_error(self): + httplib2.Http.request( + URL, METHOD, headers=mox.IgnoreArg() + ).AndRaise(Exception('error msg')) + self.mox.ReplayAll() + + self.assertRaises( + exceptions.ConnectionFailed, + self.http._cs_request, + URL, METHOD + ) + self.mox.VerifyAll() + + def test_request_success(self): + rv_should_be = MyResp(200), 'test content' + + httplib2.Http.request( + URL, METHOD, headers=mox.IgnoreArg() + ).AndReturn(rv_should_be) + self.mox.ReplayAll() + + self.assertEqual(rv_should_be, self.http._cs_request(URL, METHOD)) + self.mox.VerifyAll()