py3: port direct_client

I wanna see how far I can get *without* mucking around in swob and
request_helpers. Maybe eventually we can get some helpers out there to
make working with UTF-8-pretending-to-be-Latin-1 strings better, but for
the time being, I feel more at ease *embracing* the crazy.

Change-Id: I0b9983a182daedd9dbec483b805d263238fcfac7
Co-Authored-By: Pete Zaitcev <zaitcev@kotori.zaitcev.us>
This commit is contained in:
Tim Burke 2018-09-14 16:32:16 -06:00
parent ec66c6cbbe
commit ddd5cc1592
4 changed files with 112 additions and 165 deletions

View File

@ -54,6 +54,12 @@ class DirectClientException(ClientException):
http_reason=resp.reason, http_headers=headers)
def _make_path(*components):
return u'/' + u'/'.join(
x.decode('utf-8') if isinstance(x, six.binary_type) else x
for x in components)
def _make_req(node, part, method, path, headers, stype,
conn_timeout=5, response_timeout=15, send_timeout=15,
contents=None, content_length=None, chunk_size=65535):
@ -105,9 +111,9 @@ def _make_req(node, part, method, path, headers, stype,
if content_length is None:
chunk = contents_f.read(chunk_size)
while chunk:
conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
conn.send(b'%x\r\n%s\r\n' % (len(chunk), chunk))
chunk = contents_f.read(chunk_size)
conn.send('0\r\n\r\n')
conn.send(b'0\r\n\r\n')
else:
left = content_length
while left > 0:
@ -168,7 +174,7 @@ def _get_direct_account_container(path, stype, node, part,
if resp.status == HTTP_NO_CONTENT:
resp.read()
return resp_headers, []
return resp_headers, json.loads(resp.read())
return resp_headers, json.loads(resp.read().decode('ascii'))
def gen_headers(hdrs_in=None, add_ts=False, add_user_agent=True):
@ -200,7 +206,7 @@ def direct_get_account(node, part, account, marker=None, limit=None,
:returns: a tuple of (response headers, a list of containers) The response
headers will HeaderKeyDict.
"""
path = '/' + account
path = _make_path(account)
return _get_direct_account_container(path, "Account", node, part,
marker=marker,
limit=limit, prefix=prefix,
@ -216,7 +222,7 @@ def direct_delete_account(node, part, account, conn_timeout=5,
if headers is None:
headers = {}
path = '/%s' % account
path = _make_path(account)
_make_req(node, part, 'DELETE', path, gen_headers(headers, True),
'Account', conn_timeout, response_timeout)
@ -235,7 +241,7 @@ def direct_head_container(node, part, account, container, conn_timeout=5,
:returns: a dict containing the response's headers in a HeaderKeyDict
:raises ClientException: HTTP HEAD request failed
"""
path = '/%s/%s' % (account, container)
path = _make_path(account, container)
resp = _make_req(node, part, 'HEAD', path, gen_headers(),
'Container', conn_timeout, response_timeout)
@ -268,7 +274,7 @@ def direct_get_container(node, part, account, container, marker=None,
:returns: a tuple of (response headers, a list of objects) The response
headers will be a HeaderKeyDict.
"""
path = '/%s/%s' % (account, container)
path = _make_path(account, container)
return _get_direct_account_container(path, "Container", node,
part, marker=marker,
limit=limit, prefix=prefix,
@ -297,7 +303,7 @@ def direct_delete_container(node, part, account, container, conn_timeout=5,
if headers is None:
headers = {}
path = '/%s/%s' % (account, container)
path = _make_path(account, container)
add_timestamp = 'x-timestamp' not in (k.lower() for k in headers)
_make_req(node, part, 'DELETE', path, gen_headers(headers, add_timestamp),
'Container', conn_timeout, response_timeout)
@ -328,7 +334,7 @@ def direct_put_container(node, part, account, container, conn_timeout=5,
headers_out = gen_headers(headers,
add_ts='x-timestamp' not in lower_headers,
add_user_agent='user-agent' not in lower_headers)
path = '/%s/%s' % (account, container)
path = _make_path(account, container)
_make_req(node, part, 'PUT', path, headers_out, 'Container', conn_timeout,
response_timeout, contents=contents,
content_length=content_length, chunk_size=chunk_size)
@ -342,7 +348,7 @@ def direct_put_container_object(node, part, account, container, obj,
have_x_timestamp = 'x-timestamp' in (k.lower() for k in headers)
path = '/%s/%s/%s' % (account, container, obj)
path = _make_path(account, container, obj)
_make_req(node, part, 'PUT', path,
gen_headers(headers, add_ts=(not have_x_timestamp)),
'Container', conn_timeout, response_timeout)
@ -357,7 +363,7 @@ def direct_delete_container_object(node, part, account, container, obj,
headers = gen_headers(headers, add_ts='x-timestamp' not in (
k.lower() for k in headers))
path = '/%s/%s/%s' % (account, container, obj)
path = _make_path(account, container, obj)
_make_req(node, part, 'DELETE', path, headers,
'Container', conn_timeout, response_timeout)
@ -383,7 +389,7 @@ def direct_head_object(node, part, account, container, obj, conn_timeout=5,
headers = gen_headers(headers)
path = '/%s/%s/%s' % (account, container, obj)
path = _make_path(account, container, obj)
resp = _make_req(node, part, 'HEAD', path, headers,
'Object', conn_timeout, response_timeout)
@ -414,7 +420,7 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5,
if headers is None:
headers = {}
path = '/%s/%s/%s' % (account, container, obj)
path = _make_path(account, container, obj)
with Timeout(conn_timeout):
conn = http_connect(node['ip'], node['port'], node['device'], part,
'GET', path, headers=gen_headers(headers))
@ -464,7 +470,7 @@ def direct_put_object(node, part, account, container, name, contents,
:raises ClientException: HTTP PUT request failed
"""
path = '/%s/%s/%s' % (account, container, name)
path = _make_path(account, container, name)
if headers is None:
headers = {}
if etag:
@ -499,7 +505,7 @@ def direct_post_object(node, part, account, container, name, headers,
:param response_timeout: timeout in seconds for getting the response
:raises ClientException: HTTP POST request failed
"""
path = '/%s/%s/%s' % (account, container, name)
path = _make_path(account, container, name)
_make_req(node, part, 'POST', path, gen_headers(headers, True),
'Object', conn_timeout, response_timeout)
@ -524,7 +530,7 @@ def direct_delete_object(node, part, account, container, obj,
headers = gen_headers(headers, add_ts='x-timestamp' not in (
k.lower() for k in headers))
path = '/%s/%s/%s' % (account, container, obj)
path = _make_path(account, container, obj)
_make_req(node, part, 'DELETE', path, headers,
'Object', conn_timeout, response_timeout)

View File

@ -664,8 +664,10 @@ class FileLikeIter(object):
"""
Wraps an iterable to behave as a file-like object.
The iterable must yield bytes strings.
The iterable must be a byte string or yield byte strings.
"""
if isinstance(iterable, bytes):
iterable = (iterable, )
self.iterator = iter(iterable)
self.buf = None
self.closed = False

View File

@ -72,7 +72,7 @@ class FakeConn(object):
return self.resp_headers.items()
def read(self, amt=None):
if isinstance(self.body, six.StringIO):
if isinstance(self.body, six.BytesIO):
return self.body.read(amt)
elif amt is None:
return self.body
@ -95,11 +95,6 @@ def mocked_http_conn(*args, **kwargs):
yield fake_conn
@contextmanager
def noop_timeout(duration):
yield
@patch_policies
class TestDirectClient(unittest.TestCase):
@ -122,7 +117,14 @@ class TestDirectClient(unittest.TestCase):
self.account, self.container, self.obj))
self.user_agent = 'direct-client %s' % os.getpid()
patcher = mock.patch.object(direct_client, 'Timeout', noop_timeout)
class FakeTimeout(BaseException):
def __enter__(self):
return self
def __exit__(self, typ, value, tb):
pass
patcher = mock.patch.object(direct_client, 'Timeout', FakeTimeout)
patcher.start()
self.addCleanup(patcher.stop)
@ -178,7 +180,7 @@ class TestDirectClient(unittest.TestCase):
'X-Timestamp': '1234567890',
'X-PUT-Timestamp': '1234567890'})
body = '[{"count": 1, "bytes": 20971520, "name": "c1"}]'
body = b'[{"count": 1, "bytes": 20971520, "name": "c1"}]'
with mocked_http_conn(200, stub_headers, body) as conn:
resp_headers, resp = direct_client.direct_get_account(
@ -189,7 +191,7 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.req_headers['user-agent'],
self.user_agent)
self.assertEqual(resp_headers, stub_headers)
self.assertEqual(json.loads(body), resp)
self.assertEqual(json.loads(body.decode('ascii')), resp)
self.assertIn('format=json', conn.query_string)
for k, v in req_params.items():
if v is None:
@ -216,28 +218,23 @@ class TestDirectClient(unittest.TestCase):
stub_headers = {'X-Trans-Id': 'txb5f59485c578460f8be9e-0053478d09'}
body = 'a server error has occurred'
with mocked_http_conn(500, stub_headers, body):
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_get_account(self.node, self.part,
self.account)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(err.http_status, 500)
self.assertEqual(raised.exception.http_status, 500)
expected_err_msg_parts = (
'Account server %s:%s' % (self.node['ip'], self.node['port']),
'GET %r' % self.account_path,
'status 500',
)
for item in expected_err_msg_parts:
self.assertTrue(
item in str(err), '%r was not in "%s"' % (item, err))
self.assertEqual(err.http_host, self.node['ip'])
self.assertEqual(err.http_port, self.node['port'])
self.assertEqual(err.http_device, self.node['device'])
self.assertEqual(err.http_status, 500)
self.assertEqual(err.http_reason, 'Internal Error')
self.assertEqual(err.http_headers, stub_headers)
self.assertIn(item, str(raised.exception))
self.assertEqual(raised.exception.http_host, self.node['ip'])
self.assertEqual(raised.exception.http_port, self.node['port'])
self.assertEqual(raised.exception.http_device, self.node['device'])
self.assertEqual(raised.exception.http_status, 500)
self.assertEqual(raised.exception.http_reason, 'Internal Error')
self.assertEqual(raised.exception.http_headers, stub_headers)
def test_direct_get_account_no_content_does_not_parse_body(self):
headers = {
@ -258,17 +255,13 @@ class TestDirectClient(unittest.TestCase):
def test_direct_get_account_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_get_account(
self.node, self.part, self.account)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.method, 'GET')
self.assertEqual(conn.path, self.account_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('GET' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('GET' in str(raised.exception))
def test_direct_delete_account(self):
part = '0'
@ -296,17 +289,15 @@ class TestDirectClient(unittest.TestCase):
account = 'a'
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_delete_account(self.node, part, account)
except ClientException as err:
pass
self.assertEqual(self.node['ip'], conn.host)
self.assertEqual(self.node['port'], conn.port)
self.assertEqual('DELETE', conn.method)
self.assertEqual('/sda/0/a', conn.path)
self.assertIn('X-Timestamp', conn.req_headers)
self.assertIn('User-Agent', conn.req_headers)
self.assertEqual(err.http_status, 500)
self.assertEqual(raised.exception.http_status, 500)
def test_direct_head_container(self):
headers = HeaderKeyDict(key='value')
@ -327,13 +318,9 @@ class TestDirectClient(unittest.TestCase):
headers = HeaderKeyDict(key='value')
with mocked_http_conn(503, headers) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_head_container(
self.node, self.part, self.account, self.container)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
# check request
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
@ -341,9 +328,9 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.path, self.container_path)
self.assertEqual(conn.req_headers['user-agent'], self.user_agent)
self.assertEqual(err.http_status, 503)
self.assertEqual(err.http_headers, headers)
self.assertTrue('HEAD' in str(err))
self.assertEqual(raised.exception.http_status, 503)
self.assertEqual(raised.exception.http_headers, headers)
self.assertTrue('HEAD' in str(raised.exception))
def test_direct_head_container_deleted(self):
important_timestamp = Timestamp.now().internal
@ -351,27 +338,23 @@ class TestDirectClient(unittest.TestCase):
important_timestamp})
with mocked_http_conn(404, headers) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_head_container(
self.node, self.part, self.account, self.container)
except Exception as err:
self.assertTrue(isinstance(err, ClientException))
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'HEAD')
self.assertEqual(conn.path, self.container_path)
self.assertEqual(conn.req_headers['user-agent'], self.user_agent)
self.assertEqual(err.http_status, 404)
self.assertEqual(err.http_headers, headers)
self.assertEqual(raised.exception.http_status, 404)
self.assertEqual(raised.exception.http_headers, headers)
def test_direct_get_container(self):
def do_test(req_params):
headers = HeaderKeyDict({'key': 'value'})
body = ('[{"hash": "8f4e3", "last_modified": "317260", '
'"bytes": 209}]')
body = (b'[{"hash": "8f4e3", "last_modified": "317260", '
b'"bytes": 209}]')
with mocked_http_conn(200, headers, body) as conn:
resp_headers, resp = direct_client.direct_get_container(
@ -384,7 +367,7 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.req_headers['user-agent'],
self.user_agent)
self.assertEqual(headers, resp_headers)
self.assertEqual(json.loads(body), resp)
self.assertEqual(json.loads(body.decode('ascii')), resp)
self.assertIn('format=json', conn.query_string)
for k, v in req_params.items():
if v is None:
@ -443,24 +426,20 @@ class TestDirectClient(unittest.TestCase):
def test_direct_delete_container_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_delete_container(
self.node, self.part, self.account, self.container)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'DELETE')
self.assertEqual(conn.path, self.container_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('DELETE' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('DELETE' in str(raised.exception))
def test_direct_put_container(self):
body = 'Let us begin with a quick introduction'
body = b'Let us begin with a quick introduction'
headers = {'x-foo': 'bar', 'Content-Length': str(len(body)),
'Content-Type': 'application/json',
'User-Agent': 'my UA'}
@ -484,7 +463,7 @@ class TestDirectClient(unittest.TestCase):
self.assertIsNone(rv)
def test_direct_put_container_chunked(self):
body = 'Let us begin with a quick introduction'
body = b'Let us begin with a quick introduction'
headers = {'x-foo': 'bar', 'Content-Type': 'application/json'}
with mocked_http_conn(204) as conn:
@ -501,7 +480,7 @@ class TestDirectClient(unittest.TestCase):
self.assertTrue('x-timestamp' in conn.req_headers)
self.assertEqual('bar', conn.req_headers.get('x-foo'))
self.assertNotIn('Content-Length', conn.req_headers)
expected_sent = '%0x\r\n%s\r\n0\r\n\r\n' % (len(body), body)
expected_sent = b'%0x\r\n%s\r\n0\r\n\r\n' % (len(body), body)
self.assertEqual(md5(expected_sent).hexdigest(),
conn.etag.hexdigest())
self.assertIsNone(rv)
@ -538,22 +517,18 @@ class TestDirectClient(unittest.TestCase):
def test_direct_put_container_object_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_put_container_object(
self.node, self.part, self.account, self.container,
self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'PUT')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('PUT' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('PUT' in str(raised.exception))
def test_direct_delete_container_object(self):
with mocked_http_conn(204) as conn:
@ -568,22 +543,18 @@ class TestDirectClient(unittest.TestCase):
def test_direct_delete_container_obj_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_delete_container_object(
self.node, self.part, self.account, self.container,
self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'DELETE')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('DELETE' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('DELETE' in str(raised.exception))
def test_direct_head_object(self):
headers = HeaderKeyDict({'x-foo': 'bar'})
@ -604,45 +575,38 @@ class TestDirectClient(unittest.TestCase):
def test_direct_head_object_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_head_object(
self.node, self.part, self.account, self.container,
self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'HEAD')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('HEAD' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('HEAD' in str(raised.exception))
def test_direct_head_object_not_found(self):
important_timestamp = Timestamp.now().internal
stub_headers = {'X-Backend-Important-Timestamp': important_timestamp}
with mocked_http_conn(404, headers=stub_headers) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_head_object(
self.node, self.part, self.account, self.container,
self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'HEAD')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 404)
self.assertEqual(err.http_headers['x-backend-important-timestamp'],
important_timestamp)
self.assertEqual(raised.exception.http_status, 404)
self.assertEqual(
raised.exception.http_headers['x-backend-important-timestamp'],
important_timestamp)
def test_direct_get_object(self):
contents = six.StringIO('123456')
contents = six.BytesIO(b'123456')
with mocked_http_conn(200, body=contents) as conn:
resp_header, obj_body = direct_client.direct_get_object(
@ -655,41 +619,30 @@ class TestDirectClient(unittest.TestCase):
def test_direct_get_object_error(self):
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_get_object(
self.node, self.part,
self.account, self.container, self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'GET')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 500)
self.assertTrue('GET' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('GET' in str(raised.exception))
def test_direct_get_object_chunks(self):
contents = six.StringIO('123456')
downloaded = b''
contents = six.BytesIO(b'123456')
with mocked_http_conn(200, body=contents) as conn:
resp_header, obj_body = direct_client.direct_get_object(
self.node, self.part, self.account, self.container, self.obj,
resp_chunk_size=2)
while obj_body:
try:
chunk = obj_body.next()
except StopIteration:
break
downloaded += chunk
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual('GET', conn.method)
self.assertEqual(self.obj_path, conn.path)
self.assertEqual('123456', downloaded)
self.assertEqual([b'12', b'34', b'56'], list(obj_body))
def test_direct_post_object(self):
headers = {'Key': 'value'}
@ -712,14 +665,10 @@ class TestDirectClient(unittest.TestCase):
headers = {'Key': 'value'}
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_post_object(
self.node, self.part, self.account, self.container,
self.obj, headers)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'POST')
@ -729,8 +678,8 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.req_headers['user-agent'], self.user_agent)
self.assertTrue('x-timestamp' in conn.req_headers)
self.assertEqual(err.http_status, 500)
self.assertTrue('POST' in str(err))
self.assertEqual(raised.exception.http_status, 500)
self.assertTrue('POST' in str(raised.exception))
def test_direct_delete_object(self):
with mocked_http_conn(200) as conn:
@ -759,18 +708,14 @@ class TestDirectClient(unittest.TestCase):
def test_direct_delete_object_error(self):
with mocked_http_conn(503) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_delete_object(
self.node, self.part, self.account, self.container,
self.obj)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.method, 'DELETE')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 503)
self.assertTrue('DELETE' in str(err))
self.assertEqual(raised.exception.http_status, 503)
self.assertTrue('DELETE' in str(raised.exception))
def test_direct_get_suffix_hashes(self):
data = {'a83': 'c130a2c17ed45102aada0f4eee69494ff'}
@ -789,12 +734,12 @@ class TestDirectClient(unittest.TestCase):
with self.assertRaises(DirectClientException) as cm:
direct_client.direct_get_suffix_hashes(
self.node, self.part, ['a83', 'b52'])
self.assertIn('REPLICATE', cm.exception.message)
self.assertIn('REPLICATE', cm.exception.args[0])
self.assertIn(quote('/%s/%s/a83-b52'
% (self.node['device'], self.part)),
cm.exception.message)
self.assertIn(self.node['replication_ip'], cm.exception.message)
self.assertIn(self.node['replication_port'], cm.exception.message)
cm.exception.args[0])
self.assertIn(self.node['replication_ip'], cm.exception.args[0])
self.assertIn(self.node['replication_port'], cm.exception.args[0])
self.assertEqual(self.node['replication_ip'], cm.exception.http_host)
self.assertEqual(self.node['replication_port'], cm.exception.http_port)
self.assertEqual(self.node['device'], cm.exception.http_device)
@ -807,7 +752,7 @@ class TestDirectClient(unittest.TestCase):
self._test_direct_get_suffix_hashes_fail(507)
def test_direct_put_object_with_content_length(self):
contents = six.StringIO('123456')
contents = six.BytesIO(b'123456')
with mocked_http_conn(200) as conn:
resp = direct_client.direct_put_object(
@ -817,28 +762,24 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'PUT')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(md5('123456').hexdigest(), resp)
self.assertEqual(md5(b'123456').hexdigest(), resp)
def test_direct_put_object_fail(self):
contents = six.StringIO('123456')
contents = six.BytesIO(b'123456')
with mocked_http_conn(500) as conn:
try:
with self.assertRaises(ClientException) as raised:
direct_client.direct_put_object(
self.node, self.part, self.account, self.container,
self.obj, contents)
except ClientException as err:
pass
else:
self.fail('ClientException not raised')
self.assertEqual(conn.host, self.node['ip'])
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'PUT')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(err.http_status, 500)
self.assertEqual(raised.exception.http_status, 500)
def test_direct_put_object_chunked(self):
contents = six.StringIO('123456')
contents = six.BytesIO(b'123456')
with mocked_http_conn(200) as conn:
resp = direct_client.direct_put_object(
@ -848,7 +789,7 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.port, self.node['port'])
self.assertEqual(conn.method, 'PUT')
self.assertEqual(conn.path, self.obj_path)
self.assertEqual(md5('6\r\n123456\r\n0\r\n\r\n').hexdigest(), resp)
self.assertEqual(md5(b'6\r\n123456\r\n0\r\n\r\n').hexdigest(), resp)
def test_direct_put_object_args(self):
# One test to cover all missing checks
@ -863,10 +804,10 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(self.obj_path, conn.path)
self.assertEqual(conn.req_headers['Content-Length'], '0')
self.assertEqual(conn.req_headers['Content-Type'], 'Text')
self.assertEqual(md5('0\r\n\r\n').hexdigest(), resp)
self.assertEqual(md5(b'0\r\n\r\n').hexdigest(), resp)
def test_direct_put_object_header_content_length(self):
contents = six.StringIO('123456')
contents = six.BytesIO(b'123456')
stub_headers = HeaderKeyDict({
'Content-Length': '6'})
@ -878,7 +819,7 @@ class TestDirectClient(unittest.TestCase):
self.assertEqual(conn.port, self.node['port'])
self.assertEqual('PUT', conn.method)
self.assertEqual(conn.req_headers['Content-length'], '6')
self.assertEqual(md5('123456').hexdigest(), resp)
self.assertEqual(md5(b'123456').hexdigest(), resp)
def test_retry(self):
headers = HeaderKeyDict({'key': 'value'})
@ -905,14 +846,11 @@ class TestDirectClient(unittest.TestCase):
retries=2, error_log=logger.error)
self.assertEqual('DELETE', conn.method)
self.assertEqual(err_ctx.exception.http_status, 500)
self.assertIn('DELETE', err_ctx.exception.message)
self.assertIn(quote('/%s/%s/%s/%s/%s'
% (self.node['device'].encode('utf-8'),
self.part, self.account,
self.container, self.obj)),
err_ctx.exception.message)
self.assertIn(self.node['ip'], err_ctx.exception.message)
self.assertIn(self.node['port'], err_ctx.exception.message)
self.assertIn('DELETE', err_ctx.exception.args[0])
self.assertIn(self.obj_path,
err_ctx.exception.args[0])
self.assertIn(self.node['ip'], err_ctx.exception.args[0])
self.assertIn(self.node['port'], err_ctx.exception.args[0])
self.assertEqual(self.node['ip'], err_ctx.exception.http_host)
self.assertEqual(self.node['port'], err_ctx.exception.http_port)
self.assertEqual(self.node['device'], err_ctx.exception.http_device)

View File

@ -49,6 +49,7 @@ commands =
test/unit/common/test_bufferedhttp.py \
test/unit/common/test_constraints.py \
test/unit/common/test_daemon.py \
test/unit/common/test_direct_client.py \
test/unit/common/test_exceptions.py \
test/unit/common/test_header_key_dict.py \
test/unit/common/test_linkat.py \