Include response headers in ClientExceptions

Now, client applications can get to things like transaction IDs for
failures without needing to turn on all of logging.

While we're at it, add a from_response factory method for
ClientException.

Co-Authored-By: Alexander Corwin <ancorwin@gmail.com>
Change-Id: Ib46d5f8fc7f36f651f5908bb9d900316fdaebce3
This commit is contained in:
Tim Burke 2016-01-18 17:05:28 -08:00
parent cd3a4dbf0a
commit 9b8ab67a78
6 changed files with 158 additions and 100 deletions

@ -463,9 +463,7 @@ def get_auth_1_0(url, user, key, snet, **kwargs):
# bad URL would get you that document page and a 200. We error out # bad URL would get you that document page and a 200. We error out
# if we don't have a x-storage-url header and if we get a body. # if we don't have a x-storage-url header and if we get a body.
if resp.status < 200 or resp.status >= 300 or (body and not url): if resp.status < 200 or resp.status >= 300 or (body and not url):
raise ClientException('Auth GET failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Auth GET failed', body)
http_host=conn.host, http_path=parsed.path,
http_status=resp.status, http_reason=resp.reason)
if snet: if snet:
parsed = list(urlparse(url)) parsed = list(urlparse(url))
# Second item in the list is the netloc # Second item in the list is the netloc
@ -705,11 +703,7 @@ def get_account(url, token, marker=None, limit=None, prefix=None,
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Account GET failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Account GET failed', body)
http_host=conn.host, http_path=parsed.path,
http_query=qs, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
if resp.status == 204: if resp.status == 204:
return resp_headers, [] return resp_headers, []
return resp_headers, parse_api_response(resp_headers, body) return resp_headers, parse_api_response(resp_headers, body)
@ -741,10 +735,7 @@ def head_account(url, token, http_conn=None, service_token=None):
body = resp.read() body = resp.read()
http_log((url, method,), {'headers': headers}, resp, body) http_log((url, method,), {'headers': headers}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Account HEAD failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Account HEAD failed', body)
http_host=conn.host, http_path=parsed.path,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
return resp_headers return resp_headers
@ -786,13 +777,7 @@ def post_account(url, token, headers, http_conn=None, response_dict=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Account POST failed', raise ClientException.from_response(resp, 'Account POST failed', body)
http_scheme=parsed.scheme,
http_host=conn.host,
http_path=parsed.path,
http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
resp_headers = {} resp_headers = {}
for header, value in resp.getheaders(): for header, value in resp.getheaders():
resp_headers[header.lower()] = value resp_headers[header.lower()] = value
@ -877,11 +862,7 @@ def get_container(url, token, container, marker=None, limit=None,
{'headers': headers}, resp, body) {'headers': headers}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Container GET failed', raise ClientException.from_response(resp, 'Container GET failed', body)
http_scheme=parsed.scheme, http_host=conn.host,
http_path=cont_path, http_query=qs,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
if resp.status == 204: if resp.status == 204:
return resp_headers, [] return resp_headers, []
@ -922,11 +903,8 @@ def head_container(url, token, container, http_conn=None, headers=None,
{'headers': req_headers}, resp, body) {'headers': req_headers}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Container HEAD failed', raise ClientException.from_response(
http_scheme=parsed.scheme, http_host=conn.host, resp, 'Container HEAD failed', body)
http_path=path, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
return resp_headers return resp_headers
@ -969,11 +947,7 @@ def put_container(url, token, container, headers=None, http_conn=None,
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,), http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
{'headers': headers}, resp, body) {'headers': headers}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Container PUT failed', raise ClientException.from_response(resp, 'Container PUT failed', body)
http_scheme=parsed.scheme, http_host=conn.host,
http_path=path, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
def post_container(url, token, container, headers, http_conn=None, def post_container(url, token, container, headers, http_conn=None,
@ -1012,11 +986,8 @@ def post_container(url, token, container, headers, http_conn=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Container POST failed', raise ClientException.from_response(
http_scheme=parsed.scheme, http_host=conn.host, resp, 'Container POST failed', body)
http_path=path, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
def delete_container(url, token, container, http_conn=None, def delete_container(url, token, container, http_conn=None,
@ -1052,11 +1023,8 @@ def delete_container(url, token, container, http_conn=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Container DELETE failed', raise ClientException.from_response(
http_scheme=parsed.scheme, http_host=conn.host, resp, 'Container DELETE failed', body)
http_path=path, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
def get_object(url, token, container, name, http_conn=None, def get_object(url, token, container, name, http_conn=None,
@ -1109,11 +1077,7 @@ def get_object(url, token, container, name, http_conn=None,
body = resp.read() body = resp.read()
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,), http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
{'headers': headers}, resp, body) {'headers': headers}, resp, body)
raise ClientException('Object GET failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Object GET failed', body)
http_host=conn.host, http_path=path,
http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
if resp_chunk_size: if resp_chunk_size:
object_body = _ObjectBody(resp, resp_chunk_size) object_body = _ObjectBody(resp, resp_chunk_size)
else: else:
@ -1160,10 +1124,7 @@ def head_object(url, token, container, name, http_conn=None,
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,), http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
{'headers': headers}, resp, body) {'headers': headers}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Object HEAD failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Object HEAD failed', body)
http_host=conn.host, http_path=path,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
return resp_headers return resp_headers
@ -1275,10 +1236,7 @@ def put_object(url, token=None, container=None, name=None, contents=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Object PUT failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Object PUT failed', body)
http_host=conn.host, http_path=path,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
etag = resp.getheader('etag', '').strip('"') etag = resp.getheader('etag', '').strip('"')
return etag return etag
@ -1318,10 +1276,7 @@ def post_object(url, token, container, name, headers, http_conn=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Object POST failed', http_scheme=parsed.scheme, raise ClientException.from_response(resp, 'Object POST failed', body)
http_host=conn.host, http_path=path,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
def delete_object(url, token=None, container=None, name=None, http_conn=None, def delete_object(url, token=None, container=None, name=None, http_conn=None,
@ -1375,11 +1330,7 @@ def delete_object(url, token=None, container=None, name=None, http_conn=None,
store_response(resp, response_dict) store_response(resp, response_dict)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Object DELETE failed', raise ClientException.from_response(resp, 'Object DELETE failed', body)
http_scheme=parsed.scheme, http_host=conn.host,
http_path=path, http_status=resp.status,
http_reason=resp.reason,
http_response_content=body)
def get_capabilities(http_conn): def get_capabilities(http_conn):
@ -1396,11 +1347,8 @@ def get_capabilities(http_conn):
body = resp.read() body = resp.read()
http_log((parsed.geturl(), 'GET',), {'headers': {}}, resp, body) http_log((parsed.geturl(), 'GET',), {'headers': {}}, resp, body)
if resp.status < 200 or resp.status >= 300: if resp.status < 200 or resp.status >= 300:
raise ClientException('Capabilities GET failed', raise ClientException.from_response(
http_scheme=parsed.scheme, resp, 'Capabilities GET failed', body)
http_host=conn.host, http_path=parsed.path,
http_status=resp.status, http_reason=resp.reason,
http_response_content=body)
resp_headers = resp_header_dict(resp) resp_headers = resp_header_dict(resp)
return parse_api_response(resp_headers, body) return parse_api_response(resp_headers, body)

@ -13,12 +13,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from six.moves import urllib
class ClientException(Exception): class ClientException(Exception):
def __init__(self, msg, http_scheme='', http_host='', http_port='', def __init__(self, msg, http_scheme='', http_host='', http_port='',
http_path='', http_query='', http_status=None, http_reason='', http_path='', http_query='', http_status=None, http_reason='',
http_device='', http_response_content=''): http_device='', http_response_content='',
http_response_headers=None):
super(ClientException, self).__init__(msg) super(ClientException, self).__init__(msg)
self.msg = msg self.msg = msg
self.http_scheme = http_scheme self.http_scheme = http_scheme
@ -30,6 +33,16 @@ class ClientException(Exception):
self.http_reason = http_reason self.http_reason = http_reason
self.http_device = http_device self.http_device = http_device
self.http_response_content = http_response_content self.http_response_content = http_response_content
self.http_response_headers = http_response_headers
@classmethod
def from_response(cls, resp, msg=None, body=None):
msg = msg or '%s %s' % (resp.status_code, resp.reason)
body = body or resp.content
parsed_url = urllib.parse.urlparse(resp.request.url)
return cls(msg, parsed_url.scheme, parsed_url.hostname,
parsed_url.port, parsed_url.path, parsed_url.query,
resp.status_code, resp.reason, '', body, resp.headers)
def __str__(self): def __str__(self):
a = self.msg a = self.msg

@ -33,7 +33,8 @@ from swiftclient.utils import config_true_value, generate_temp_url, prt_bytes
from swiftclient.multithreading import OutputManager from swiftclient.multithreading import OutputManager
from swiftclient.exceptions import ClientException from swiftclient.exceptions import ClientException
from swiftclient import __version__ as client_version from swiftclient import __version__ as client_version
from swiftclient.client import logger_settings as client_logger_settings from swiftclient.client import logger_settings as client_logger_settings, \
parse_header_string
from swiftclient.service import SwiftService, SwiftError, \ from swiftclient.service import SwiftService, SwiftError, \
SwiftUploadObject, get_conn SwiftUploadObject, get_conn
from swiftclient.command_helpers import print_account_stats, \ from swiftclient.command_helpers import print_account_stats, \
@ -1475,7 +1476,13 @@ Examples:
parser.usage = globals()['st_%s_help' % args[0]] parser.usage = globals()['st_%s_help' % args[0]]
try: try:
globals()['st_%s' % args[0]](parser, argv[1:], output) globals()['st_%s' % args[0]](parser, argv[1:], output)
except (ClientException, RequestException, socket.error) as err: except ClientException as err:
output.error(str(err))
trans_id = (err.http_response_headers or {}).get('X-Trans-Id')
if trans_id:
output.error("Failed Transaction ID: %s",
parse_header_string(trans_id))
except (RequestException, socket.error) as err:
output.error(str(err)) output.error(str(err))
if output.get_error_count() > 0: if output.get_error_count() > 0:

@ -1073,13 +1073,42 @@ class TestShell(unittest.TestCase):
def test_post_account_bad_auth(self, connection): def test_post_account_bad_auth(self, connection):
argv = ["", "post"] argv = ["", "post"]
connection.return_value.post_account.side_effect = \ connection.return_value.post_account.side_effect = \
swiftclient.ClientException('bad auth') swiftclient.ClientException(
'bad auth', http_response_headers={'X-Trans-Id': 'trans_id'})
with CaptureOutput() as output: with CaptureOutput() as output:
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
swiftclient.shell.main(argv) swiftclient.shell.main(argv)
self.assertEqual(output.err, 'bad auth\n') self.assertEqual(output.err,
'bad auth\nFailed Transaction ID: trans_id\n')
# do it again with a unicode token
connection.return_value.post_account.side_effect = \
swiftclient.ClientException(
'bad auth', http_response_headers={
'X-Trans-Id': 'non\u2011utf8'})
with CaptureOutput() as output:
with self.assertRaises(SystemExit):
swiftclient.shell.main(argv)
self.assertEqual(output.err,
'bad auth\n'
'Failed Transaction ID: non\u2011utf8\n')
# do it again with a wonky token
connection.return_value.post_account.side_effect = \
swiftclient.ClientException(
'bad auth', http_response_headers={
'X-Trans-Id': b'non\xffutf8'})
with CaptureOutput() as output:
with self.assertRaises(SystemExit):
swiftclient.shell.main(argv)
self.assertEqual(output.err,
'bad auth\nFailed Transaction ID: non%FFutf8\n')
@mock.patch('swiftclient.service.Connection') @mock.patch('swiftclient.service.Connection')
def test_post_account_not_found(self, connection): def test_post_account_not_found(self, connection):

@ -51,6 +51,7 @@ class TestClientException(unittest.TestCase):
'status', 'status',
'reason', 'reason',
'device', 'device',
'response_content',
) )
for value in test_kwargs: for value in test_kwargs:
kwargs = { kwargs = {
@ -59,6 +60,26 @@ class TestClientException(unittest.TestCase):
exc = c.ClientException('test', **kwargs) exc = c.ClientException('test', **kwargs)
self.assertIn(value, str(exc)) self.assertIn(value, str(exc))
def test_attrs(self):
test_kwargs = (
'scheme',
'host',
'port',
'path',
'query',
'status',
'reason',
'device',
'response_content',
'response_headers',
)
for value in test_kwargs:
key = 'http_%s' % value
kwargs = {key: value}
exc = c.ClientException('test', **kwargs)
self.assertIs(True, hasattr(exc, key))
self.assertEqual(getattr(exc, key), value)
class MockHttpResponse(object): class MockHttpResponse(object):
def __init__(self, status=0, headers=None, verify=False): def __init__(self, status=0, headers=None, verify=False):
@ -582,7 +603,9 @@ class TestHeadAccount(MockHttpTest):
def test_server_error(self): def test_server_error(self):
body = 'c' * 65 body = 'c' * 65
c.http_connection = self.fake_http_connection(500, body=body) headers = {'foo': 'bar'}
c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context: with self.assertRaises(c.ClientException) as exc_context:
c.head_account('http://www.tests.com', 'asdf') c.head_account('http://www.tests.com', 'asdf')
e = exc_context.exception e = exc_context.exception
@ -741,7 +764,9 @@ class TestHeadContainer(MockHttpTest):
def test_server_error(self): def test_server_error(self):
body = 'c' * 60 body = 'c' * 60
c.http_connection = self.fake_http_connection(500, body=body) headers = {'foo': 'bar'}
c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context: with self.assertRaises(c.ClientException) as exc_context:
c.head_container('http://www.test.com', 'asdf', 'container') c.head_container('http://www.test.com', 'asdf', 'container')
e = exc_context.exception e = exc_context.exception
@ -750,6 +775,7 @@ class TestHeadContainer(MockHttpTest):
]) ])
self.assertEqual(e.http_status, 500) self.assertEqual(e.http_status, 500)
self.assertEqual(e.http_response_content, body) self.assertEqual(e.http_response_content, body)
self.assertEqual(e.http_response_headers, headers)
class TestPutContainer(MockHttpTest): class TestPutContainer(MockHttpTest):
@ -766,10 +792,13 @@ class TestPutContainer(MockHttpTest):
def test_server_error(self): def test_server_error(self):
body = 'c' * 60 body = 'c' * 60
c.http_connection = self.fake_http_connection(500, body=body) headers = {'foo': 'bar'}
c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context: with self.assertRaises(c.ClientException) as exc_context:
c.put_container('http://www.test.com', 'token', 'container') c.put_container('http://www.test.com', 'token', 'container')
self.assertEqual(exc_context.exception.http_response_content, body) self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
self.assertRequests([ self.assertRequests([
('PUT', '/container', '', { ('PUT', '/container', '', {
'x-auth-token': 'token', 'x-auth-token': 'token',
@ -792,9 +821,14 @@ class TestDeleteContainer(MockHttpTest):
class TestGetObject(MockHttpTest): class TestGetObject(MockHttpTest):
def test_server_error(self): def test_server_error(self):
c.http_connection = self.fake_http_connection(500) body = 'c' * 60
self.assertRaises(c.ClientException, c.get_object, headers = {'foo': 'bar'}
'http://www.test.com', 'asdf', 'asdf', 'asdf') c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context:
c.get_object('http://www.test.com', 'asdf', 'asdf', 'asdf')
self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
def test_query_string(self): def test_query_string(self):
c.http_connection = self.fake_http_connection(200, c.http_connection = self.fake_http_connection(200,
@ -945,9 +979,14 @@ class TestGetObject(MockHttpTest):
class TestHeadObject(MockHttpTest): class TestHeadObject(MockHttpTest):
def test_server_error(self): def test_server_error(self):
c.http_connection = self.fake_http_connection(500) body = 'c' * 60
self.assertRaises(c.ClientException, c.head_object, headers = {'foo': 'bar'}
'http://www.test.com', 'asdf', 'asdf', 'asdf') c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context:
c.head_object('http://www.test.com', 'asdf', 'asdf', 'asdf')
self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
def test_request_headers(self): def test_request_headers(self):
c.http_connection = self.fake_http_connection(204) c.http_connection = self.fake_http_connection(204)
@ -1024,12 +1063,15 @@ class TestPutObject(MockHttpTest):
def test_server_error(self): def test_server_error(self):
body = 'c' * 60 body = 'c' * 60
c.http_connection = self.fake_http_connection(500, body=body) headers = {'foo': 'bar'}
c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
args = ('http://www.test.com', 'asdf', 'asdf', 'asdf', 'asdf') args = ('http://www.test.com', 'asdf', 'asdf', 'asdf', 'asdf')
with self.assertRaises(c.ClientException) as exc_context: with self.assertRaises(c.ClientException) as exc_context:
c.put_object(*args) c.put_object(*args)
e = exc_context.exception e = exc_context.exception
self.assertEqual(e.http_response_content, body) self.assertEqual(e.http_response_content, body)
self.assertEqual(e.http_response_headers, headers)
self.assertEqual(e.http_status, 500) self.assertEqual(e.http_status, 500)
self.assertRequests([ self.assertRequests([
('PUT', '/asdf/asdf', 'asdf', { ('PUT', '/asdf/asdf', 'asdf', {
@ -1249,11 +1291,14 @@ class TestPostObject(MockHttpTest):
def test_server_error(self): def test_server_error(self):
body = 'c' * 60 body = 'c' * 60
c.http_connection = self.fake_http_connection(500, body=body) headers = {'foo': 'bar'}
c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
args = ('http://www.test.com', 'token', 'container', 'obj', {}) args = ('http://www.test.com', 'token', 'container', 'obj', {})
with self.assertRaises(c.ClientException) as exc_context: with self.assertRaises(c.ClientException) as exc_context:
c.post_object(*args) c.post_object(*args)
self.assertEqual(exc_context.exception.http_response_content, body) self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
self.assertRequests([ self.assertRequests([
('POST', 'http://www.test.com/container/obj', '', { ('POST', 'http://www.test.com/container/obj', '', {
'x-auth-token': 'token', 'x-auth-token': 'token',
@ -1273,9 +1318,14 @@ class TestDeleteObject(MockHttpTest):
]) ])
def test_server_error(self): def test_server_error(self):
c.http_connection = self.fake_http_connection(500) body = 'c' * 60
self.assertRaises(c.ClientException, c.delete_object, headers = {'foo': 'bar'}
'http://www.test.com', 'asdf', 'asdf', 'asdf') c.http_connection = self.fake_http_connection(
StubResponse(500, body, headers))
with self.assertRaises(c.ClientException) as exc_context:
c.delete_object('http://www.test.com', 'asdf', 'asdf', 'asdf')
self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
def test_query_string(self): def test_query_string(self):
c.http_connection = self.fake_http_connection(200, c.http_connection = self.fake_http_connection(200,
@ -1302,9 +1352,15 @@ class TestGetCapabilities(MockHttpTest):
self.assertTrue(http_conn[1].resp.has_been_read) self.assertTrue(http_conn[1].resp.has_been_read)
def test_server_error(self): def test_server_error(self):
conn = self.fake_http_connection(500) body = 'c' * 60
headers = {'foo': 'bar'}
conn = self.fake_http_connection(
StubResponse(500, body, headers))
http_conn = conn('http://www.test.com/info') http_conn = conn('http://www.test.com/info')
self.assertRaises(c.ClientException, c.get_capabilities, http_conn) with self.assertRaises(c.ClientException) as exc_context:
c.get_capabilities(http_conn)
self.assertEqual(exc_context.exception.http_response_content, body)
self.assertEqual(exc_context.exception.http_response_headers, headers)
def test_conn_get_capabilities_with_auth(self): def test_conn_get_capabilities_with_auth(self):
auth_headers = { auth_headers = {

@ -87,17 +87,19 @@ def fake_http_connect(*code_iter, **kwargs):
def __init__(self, status, etag=None, body='', timestamp='1', def __init__(self, status, etag=None, body='', timestamp='1',
headers=None): headers=None):
self.status = status self.status_code = self.status = status
self.reason = 'Fake' self.reason = 'Fake'
self.scheme = 'http'
self.host = '1.2.3.4' self.host = '1.2.3.4'
self.port = '1234' self.port = '1234'
self.sent = 0 self.sent = 0
self.received = 0 self.received = 0
self.etag = etag self.etag = etag
self.body = body self.content = self.body = body
self.timestamp = timestamp self.timestamp = timestamp
self._is_closed = True self._is_closed = True
self.headers = headers or {} self.headers = headers or {}
self.request = None
def getresponse(self): def getresponse(self):
if kwargs.get('raise_exc'): if kwargs.get('raise_exc'):
@ -223,15 +225,18 @@ class MockHttpTest(unittest.TestCase):
pass pass
conn = RequestsWrapper() conn = RequestsWrapper()
def request(method, url, *args, **kwargs): def request(method, path, *args, **kwargs):
try: try:
conn.resp = self.fake_connect() conn.resp = self.fake_connect()
except StopIteration: except StopIteration:
self.fail('Unexpected %s request for %s' % ( self.fail('Unexpected %s request for %s' % (
method, url)) method, path))
self.request_log.append((parsed, method, url, args, self.request_log.append((parsed, method, path, args,
kwargs, conn.resp)) kwargs, conn.resp))
conn.host = conn.resp.host conn.host = conn.resp.host
conn.resp.request = RequestsWrapper()
conn.resp.request.url = '%s://%s%s' % (
conn.resp.scheme, conn.resp.host, path)
conn.resp.has_been_read = False conn.resp.has_been_read = False
_orig_read = conn.resp.read _orig_read = conn.resp.read
@ -240,15 +245,15 @@ class MockHttpTest(unittest.TestCase):
return _orig_read(*args, **kwargs) return _orig_read(*args, **kwargs)
conn.resp.read = read conn.resp.read = read
if on_request: if on_request:
status = on_request(method, url, *args, **kwargs) status = on_request(method, path, *args, **kwargs)
conn.resp.status = status conn.resp.status = status
if auth_token: if auth_token:
headers = args[1] headers = args[1]
self.assertEqual(auth_token, self.assertEqual(auth_token,
headers.get('X-Auth-Token')) headers.get('X-Auth-Token'))
if query_string: if query_string:
self.assertTrue(url.endswith('?' + query_string)) self.assertTrue(path.endswith('?' + query_string))
if url.endswith('invalid_cert') and not insecure: if path.endswith('invalid_cert') and not insecure:
from swiftclient import client as c from swiftclient import client as c
raise c.ClientException("invalid_certificate") raise c.ClientException("invalid_certificate")
if exc: if exc: