Merge "py3: port internal_client"
This commit is contained in:
@@ -28,7 +28,7 @@ from zlib import compressobj
|
|||||||
from swift.common.exceptions import ClientException
|
from swift.common.exceptions import ClientException
|
||||||
from swift.common.http import (HTTP_NOT_FOUND, HTTP_MULTIPLE_CHOICES,
|
from swift.common.http import (HTTP_NOT_FOUND, HTTP_MULTIPLE_CHOICES,
|
||||||
is_server_error)
|
is_server_error)
|
||||||
from swift.common.swob import Request
|
from swift.common.swob import Request, bytes_to_wsgi
|
||||||
from swift.common.utils import quote, closing_if_possible
|
from swift.common.utils import quote, closing_if_possible
|
||||||
from swift.common.wsgi import loadapp, pipeline_property
|
from swift.common.wsgi import loadapp, pipeline_property
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ class CompressingFileReader(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if self.done:
|
if self.done:
|
||||||
return ''
|
return b''
|
||||||
x = self._f.read(*a, **kw)
|
x = self._f.read(*a, **kw)
|
||||||
if x:
|
if x:
|
||||||
self.crc32 = zlib.crc32(x, self.crc32) & 0xffffffff
|
self.crc32 = zlib.crc32(x, self.crc32) & 0xffffffff
|
||||||
@@ -112,19 +112,21 @@ class CompressingFileReader(object):
|
|||||||
self.done = True
|
self.done = True
|
||||||
if self.first:
|
if self.first:
|
||||||
self.first = False
|
self.first = False
|
||||||
header = '\037\213\010\000\000\000\000\000\002\377'
|
header = b'\037\213\010\000\000\000\000\000\002\377'
|
||||||
compressed = header + compressed
|
compressed = header + compressed
|
||||||
return compressed
|
return compressed
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
chunk = self.read(self.chunk_size)
|
chunk = self.read(self.chunk_size)
|
||||||
if chunk:
|
if chunk:
|
||||||
return chunk
|
return chunk
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
|
next = __next__
|
||||||
|
|
||||||
def seek(self, offset, whence=0):
|
def seek(self, offset, whence=0):
|
||||||
if not (offset == 0 and whence == 0):
|
if not (offset == 0 and whence == 0):
|
||||||
raise NotImplementedError('Seek implemented on offset 0 only')
|
raise NotImplementedError('Seek implemented on offset 0 only')
|
||||||
@@ -278,17 +280,25 @@ class InternalClient(object):
|
|||||||
:raises Exception: Exception is raised when code fails in an
|
:raises Exception: Exception is raised when code fails in an
|
||||||
unexpected way.
|
unexpected way.
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(marker, bytes):
|
||||||
|
marker = marker.encode('utf8')
|
||||||
|
if not isinstance(end_marker, bytes):
|
||||||
|
end_marker = end_marker.encode('utf8')
|
||||||
|
if not isinstance(prefix, bytes):
|
||||||
|
prefix = prefix.encode('utf8')
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
resp = self.make_request(
|
resp = self.make_request(
|
||||||
'GET', '%s?format=json&marker=%s&end_marker=%s&prefix=%s' %
|
'GET', '%s?format=json&marker=%s&end_marker=%s&prefix=%s' %
|
||||||
(path, quote(marker), quote(end_marker), quote(prefix)),
|
(path, bytes_to_wsgi(quote(marker)),
|
||||||
|
bytes_to_wsgi(quote(end_marker)),
|
||||||
|
bytes_to_wsgi(quote(prefix))),
|
||||||
{}, acceptable_statuses)
|
{}, acceptable_statuses)
|
||||||
if not resp.status_int == 200:
|
if not resp.status_int == 200:
|
||||||
if resp.status_int >= HTTP_MULTIPLE_CHOICES:
|
if resp.status_int >= HTTP_MULTIPLE_CHOICES:
|
||||||
''.join(resp.app_iter)
|
b''.join(resp.app_iter)
|
||||||
break
|
break
|
||||||
data = json.loads(resp.body)
|
data = json.loads(resp.body.decode('ascii'))
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
for item in data:
|
for item in data:
|
||||||
@@ -687,7 +697,7 @@ class InternalClient(object):
|
|||||||
if not resp.status_int // 100 == 2:
|
if not resp.status_int // 100 == 2:
|
||||||
return
|
return
|
||||||
|
|
||||||
last_part = ''
|
last_part = b''
|
||||||
compressed = obj.endswith('.gz')
|
compressed = obj.endswith('.gz')
|
||||||
# magic in the following zlib.decompressobj argument is courtesy of
|
# magic in the following zlib.decompressobj argument is courtesy of
|
||||||
# Python decompressing gzip chunk-by-chunk
|
# Python decompressing gzip chunk-by-chunk
|
||||||
@@ -696,7 +706,7 @@ class InternalClient(object):
|
|||||||
for chunk in resp.app_iter:
|
for chunk in resp.app_iter:
|
||||||
if compressed:
|
if compressed:
|
||||||
chunk = d.decompress(chunk)
|
chunk = d.decompress(chunk)
|
||||||
parts = chunk.split('\n')
|
parts = chunk.split(b'\n')
|
||||||
if len(parts) == 1:
|
if len(parts) == 1:
|
||||||
last_part = last_part + parts[0]
|
last_part = last_part + parts[0]
|
||||||
else:
|
else:
|
||||||
@@ -834,7 +844,7 @@ class SimpleClient(object):
|
|||||||
body = conn.read()
|
body = conn.read()
|
||||||
info = conn.info()
|
info = conn.info()
|
||||||
try:
|
try:
|
||||||
body_data = json.loads(body)
|
body_data = json.loads(body.decode('ascii'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
body_data = None
|
body_data = None
|
||||||
trans_stop = time()
|
trans_stop = time()
|
||||||
|
@@ -29,6 +29,8 @@ from test.unit import FakeLogger, FakeRing
|
|||||||
|
|
||||||
class LeakTrackingIter(object):
|
class LeakTrackingIter(object):
|
||||||
def __init__(self, inner_iter, mark_closed, path):
|
def __init__(self, inner_iter, mark_closed, path):
|
||||||
|
if isinstance(inner_iter, bytes):
|
||||||
|
inner_iter = (inner_iter, )
|
||||||
self.inner_iter = inner_iter
|
self.inner_iter = inner_iter
|
||||||
self.mark_closed = mark_closed
|
self.mark_closed = mark_closed
|
||||||
self.path = path
|
self.path = path
|
||||||
|
@@ -19,11 +19,10 @@ import unittest
|
|||||||
import zlib
|
import zlib
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
import os
|
import os
|
||||||
from itertools import izip_longest
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six import StringIO
|
from six import BytesIO
|
||||||
from six.moves import range
|
from six.moves import range, zip_longest
|
||||||
from six.moves.urllib.parse import quote, parse_qsl
|
from six.moves.urllib.parse import quote, parse_qsl
|
||||||
from test.unit import FakeLogger
|
from test.unit import FakeLogger
|
||||||
from swift.common import exceptions, internal_client, swob
|
from swift.common import exceptions, internal_client, swob
|
||||||
@@ -48,7 +47,7 @@ class FakeConn(object):
|
|||||||
self.body = body
|
self.body = body
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
return json.dumps(self.body)
|
return json.dumps(self.body).encode('ascii')
|
||||||
|
|
||||||
def info(self):
|
def info(self):
|
||||||
return {}
|
return {}
|
||||||
@@ -82,7 +81,7 @@ def make_path_info(account, container=None, obj=None):
|
|||||||
# FakeSwift keys on PATH_INFO - which is *encoded* but unquoted
|
# FakeSwift keys on PATH_INFO - which is *encoded* but unquoted
|
||||||
path = '/v1/%s' % '/'.join(
|
path = '/v1/%s' % '/'.join(
|
||||||
p for p in (account, container, obj) if p)
|
p for p in (account, container, obj) if p)
|
||||||
return path.encode('utf-8')
|
return swob.bytes_to_wsgi(path.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
def get_client_app():
|
def get_client_app():
|
||||||
@@ -179,7 +178,7 @@ class TestCompressingfileReader(unittest.TestCase):
|
|||||||
old_compressobj = internal_client.compressobj
|
old_compressobj = internal_client.compressobj
|
||||||
internal_client.compressobj = compressobj.method
|
internal_client.compressobj = compressobj.method
|
||||||
|
|
||||||
f = StringIO('')
|
f = BytesIO(b'')
|
||||||
|
|
||||||
fobj = internal_client.CompressingFileReader(f)
|
fobj = internal_client.CompressingFileReader(f)
|
||||||
self.assertEqual(f, fobj._f)
|
self.assertEqual(f, fobj._f)
|
||||||
@@ -192,21 +191,20 @@ class TestCompressingfileReader(unittest.TestCase):
|
|||||||
internal_client.compressobj = old_compressobj
|
internal_client.compressobj = old_compressobj
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
exp_data = 'abcdefghijklmnopqrstuvwxyz'
|
exp_data = b'abcdefghijklmnopqrstuvwxyz'
|
||||||
fobj = internal_client.CompressingFileReader(
|
fobj = internal_client.CompressingFileReader(
|
||||||
StringIO(exp_data), chunk_size=5)
|
BytesIO(exp_data), chunk_size=5)
|
||||||
|
|
||||||
data = ''
|
|
||||||
d = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
d = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||||
for chunk in fobj.read():
|
data = b''.join(d.decompress(chunk)
|
||||||
data += d.decompress(chunk)
|
for chunk in iter(fobj.read, b''))
|
||||||
|
|
||||||
self.assertEqual(exp_data, data)
|
self.assertEqual(exp_data, data)
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek(self):
|
||||||
exp_data = 'abcdefghijklmnopqrstuvwxyz'
|
exp_data = b'abcdefghijklmnopqrstuvwxyz'
|
||||||
fobj = internal_client.CompressingFileReader(
|
fobj = internal_client.CompressingFileReader(
|
||||||
StringIO(exp_data), chunk_size=5)
|
BytesIO(exp_data), chunk_size=5)
|
||||||
|
|
||||||
# read a couple of chunks only
|
# read a couple of chunks only
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
@@ -214,15 +212,14 @@ class TestCompressingfileReader(unittest.TestCase):
|
|||||||
|
|
||||||
# read whole thing after seek and check data
|
# read whole thing after seek and check data
|
||||||
fobj.seek(0)
|
fobj.seek(0)
|
||||||
data = ''
|
|
||||||
d = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
d = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||||
for chunk in fobj.read():
|
data = b''.join(d.decompress(chunk)
|
||||||
data += d.decompress(chunk)
|
for chunk in iter(fobj.read, b''))
|
||||||
self.assertEqual(exp_data, data)
|
self.assertEqual(exp_data, data)
|
||||||
|
|
||||||
def test_seek_not_implemented_exception(self):
|
def test_seek_not_implemented_exception(self):
|
||||||
fobj = internal_client.CompressingFileReader(
|
fobj = internal_client.CompressingFileReader(
|
||||||
StringIO(''), chunk_size=5)
|
BytesIO(b''), chunk_size=5)
|
||||||
self.assertRaises(NotImplementedError, fobj.seek, 10)
|
self.assertRaises(NotImplementedError, fobj.seek, 10)
|
||||||
self.assertRaises(NotImplementedError, fobj.seek, 0, 10)
|
self.assertRaises(NotImplementedError, fobj.seek, 0, 10)
|
||||||
|
|
||||||
@@ -412,13 +409,22 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
_, resp_body = sc.base_request('GET', full_listing=True)
|
_, resp_body = sc.base_request('GET', full_listing=True)
|
||||||
self.assertEqual(body1 + body2, resp_body)
|
self.assertEqual(body1 + body2, resp_body)
|
||||||
self.assertEqual(3, mock_urlopen.call_count)
|
self.assertEqual(3, mock_urlopen.call_count)
|
||||||
actual_requests = map(
|
actual_requests = [call[0][0] for call in mock_urlopen.call_args_list]
|
||||||
lambda call: call[0][0], mock_urlopen.call_args_list)
|
if six.PY2:
|
||||||
self.assertEqual('/?format=json', actual_requests[0].get_selector())
|
# The get_selector method was deprecated in favor of a selector
|
||||||
|
# attribute in py31 and removed in py34
|
||||||
|
self.assertEqual(
|
||||||
|
'/?format=json', actual_requests[0].get_selector())
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'/?format=json&marker=c', actual_requests[1].get_selector())
|
'/?format=json&marker=c', actual_requests[1].get_selector())
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'/?format=json&marker=d', actual_requests[2].get_selector())
|
'/?format=json&marker=d', actual_requests[2].get_selector())
|
||||||
|
else:
|
||||||
|
self.assertEqual('/?format=json', actual_requests[0].selector)
|
||||||
|
self.assertEqual(
|
||||||
|
'/?format=json&marker=c', actual_requests[1].selector)
|
||||||
|
self.assertEqual(
|
||||||
|
'/?format=json&marker=d', actual_requests[2].selector)
|
||||||
|
|
||||||
def test_make_request_method_path_headers(self):
|
def test_make_request_method_path_headers(self):
|
||||||
class InternalClient(internal_client.InternalClient):
|
class InternalClient(internal_client.InternalClient):
|
||||||
@@ -455,7 +461,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.request_tries = 3
|
self.request_tries = 3
|
||||||
|
|
||||||
def fake_app(self, env, start_response):
|
def fake_app(self, env, start_response):
|
||||||
body = 'fake error response'
|
body = b'fake error response'
|
||||||
start_response('409 Conflict',
|
start_response('409 Conflict',
|
||||||
[('Content-Length', str(len(body)))])
|
[('Content-Length', str(len(body)))])
|
||||||
return [body]
|
return [body]
|
||||||
@@ -469,7 +475,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
# succeed (assuming the failure was due to clock skew between servers)
|
# succeed (assuming the failure was due to clock skew between servers)
|
||||||
expected = (' HTTP/1.0 409 ',)
|
expected = (' HTTP/1.0 409 ',)
|
||||||
loglines = client.logger.get_lines_for_level('info')
|
loglines = client.logger.get_lines_for_level('info')
|
||||||
for expected, logline in izip_longest(expected, loglines):
|
for expected, logline in zip_longest(expected, loglines):
|
||||||
if not expected:
|
if not expected:
|
||||||
self.fail('Unexpected extra log line: %r' % logline)
|
self.fail('Unexpected extra log line: %r' % logline)
|
||||||
self.assertIn(expected, logline)
|
self.assertIn(expected, logline)
|
||||||
@@ -487,7 +493,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.closed_paths = []
|
self.closed_paths = []
|
||||||
|
|
||||||
def fake_app(self, env, start_response):
|
def fake_app(self, env, start_response):
|
||||||
body = 'fake error response'
|
body = b'fake error response'
|
||||||
start_response(self.resp_status,
|
start_response(self.resp_status,
|
||||||
[('Content-Length', str(len(body)))])
|
[('Content-Length', str(len(body)))])
|
||||||
return LeakTrackingIter(body, self.closed_paths.append,
|
return LeakTrackingIter(body, self.closed_paths.append,
|
||||||
@@ -509,11 +515,11 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.assertEqual(closed_paths, [])
|
self.assertEqual(closed_paths, [])
|
||||||
# ...and it'll be on us (the caller) to close (for example, by using
|
# ...and it'll be on us (the caller) to close (for example, by using
|
||||||
# swob.Response's body property)
|
# swob.Response's body property)
|
||||||
self.assertEqual(resp.body, 'fake error response')
|
self.assertEqual(resp.body, b'fake error response')
|
||||||
self.assertEqual(closed_paths, ['/cont/obj'])
|
self.assertEqual(closed_paths, ['/cont/obj'])
|
||||||
|
|
||||||
expected = (' HTTP/1.0 200 ', )
|
expected = (' HTTP/1.0 200 ', )
|
||||||
for expected, logline in izip_longest(expected, loglines):
|
for expected, logline in zip_longest(expected, loglines):
|
||||||
if not expected:
|
if not expected:
|
||||||
self.fail('Unexpected extra log line: %r' % logline)
|
self.fail('Unexpected extra log line: %r' % logline)
|
||||||
self.assertIn(expected, logline)
|
self.assertIn(expected, logline)
|
||||||
@@ -524,7 +530,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.assertEqual(closed_paths, ['/cont/obj'] * 3)
|
self.assertEqual(closed_paths, ['/cont/obj'] * 3)
|
||||||
|
|
||||||
expected = (' HTTP/1.0 503 ', ' HTTP/1.0 503 ', ' HTTP/1.0 503 ', )
|
expected = (' HTTP/1.0 503 ', ' HTTP/1.0 503 ', ' HTTP/1.0 503 ', )
|
||||||
for expected, logline in izip_longest(expected, loglines):
|
for expected, logline in zip_longest(expected, loglines):
|
||||||
if not expected:
|
if not expected:
|
||||||
self.fail('Unexpected extra log line: %r' % logline)
|
self.fail('Unexpected extra log line: %r' % logline)
|
||||||
self.assertIn(expected, logline)
|
self.assertIn(expected, logline)
|
||||||
@@ -551,22 +557,21 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
client.make_request('GET', '/', {}, (400, 200))
|
client.make_request('GET', '/', {}, (400, 200))
|
||||||
client.make_request('GET', '/', {}, (400, 2))
|
client.make_request('GET', '/', {}, (400, 2))
|
||||||
|
|
||||||
try:
|
with self.assertRaises(internal_client.UnexpectedResponse) \
|
||||||
|
as raised:
|
||||||
client.make_request('GET', '/', {}, (400,))
|
client.make_request('GET', '/', {}, (400,))
|
||||||
except Exception as err:
|
self.assertEqual(200, raised.exception.resp.status_int)
|
||||||
pass
|
|
||||||
self.assertEqual(200, err.resp.status_int)
|
with self.assertRaises(internal_client.UnexpectedResponse) \
|
||||||
try:
|
as raised:
|
||||||
client.make_request('GET', '/', {}, (201,))
|
client.make_request('GET', '/', {}, (201,))
|
||||||
except Exception as err:
|
self.assertEqual(200, raised.exception.resp.status_int)
|
||||||
pass
|
|
||||||
self.assertEqual(200, err.resp.status_int)
|
with self.assertRaises(internal_client.UnexpectedResponse) \
|
||||||
try:
|
as raised:
|
||||||
client.make_request('GET', '/', {}, (111,))
|
client.make_request('GET', '/', {}, (111,))
|
||||||
except Exception as err:
|
self.assertTrue(str(raised.exception).startswith(
|
||||||
self.assertTrue(str(err).startswith('Unexpected response'))
|
'Unexpected response'))
|
||||||
else:
|
|
||||||
self.fail("Expected the UnexpectedResponse")
|
|
||||||
finally:
|
finally:
|
||||||
internal_client.sleep = old_sleep
|
internal_client.sleep = old_sleep
|
||||||
|
|
||||||
@@ -681,7 +686,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
|
|
||||||
def fake_app(self, environ, start_response):
|
def fake_app(self, environ, start_response):
|
||||||
start_response('404 Not Found', [('x-foo', 'bar')])
|
start_response('404 Not Found', [('x-foo', 'bar')])
|
||||||
return ['nope']
|
return [b'nope']
|
||||||
|
|
||||||
client = InternalClient()
|
client = InternalClient()
|
||||||
self.assertRaises(internal_client.UnexpectedResponse,
|
self.assertRaises(internal_client.UnexpectedResponse,
|
||||||
@@ -720,7 +725,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
return self.responses.pop(0)
|
return self.responses.pop(0)
|
||||||
|
|
||||||
exp_items = []
|
exp_items = []
|
||||||
responses = [Response(200, json.dumps([])), ]
|
responses = [Response(200, json.dumps([]).encode('ascii')), ]
|
||||||
items = []
|
items = []
|
||||||
client = InternalClient(self, responses)
|
client = InternalClient(self, responses)
|
||||||
for item in client._iter_items('/'):
|
for item in client._iter_items('/'):
|
||||||
@@ -733,7 +738,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
data = [
|
data = [
|
||||||
{'name': 'item%02d' % (2 * i)},
|
{'name': 'item%02d' % (2 * i)},
|
||||||
{'name': 'item%02d' % (2 * i + 1)}]
|
{'name': 'item%02d' % (2 * i + 1)}]
|
||||||
responses.append(Response(200, json.dumps(data)))
|
responses.append(Response(200, json.dumps(data).encode('ascii')))
|
||||||
exp_items.extend(data)
|
exp_items.extend(data)
|
||||||
responses.append(Response(204, ''))
|
responses.append(Response(204, ''))
|
||||||
|
|
||||||
@@ -747,7 +752,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
class Response(object):
|
class Response(object):
|
||||||
def __init__(self, status_int, body):
|
def __init__(self, status_int, body):
|
||||||
self.status_int = status_int
|
self.status_int = status_int
|
||||||
self.body = body
|
self.body = body.encode('ascii')
|
||||||
|
|
||||||
class InternalClient(internal_client.InternalClient):
|
class InternalClient(internal_client.InternalClient):
|
||||||
def __init__(self, test, paths, responses):
|
def __init__(self, test, paths, responses):
|
||||||
@@ -769,7 +774,8 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
responses = [
|
responses = [
|
||||||
Response(200, json.dumps([{'name': 'one\xc3\xa9'}, ])),
|
Response(200, json.dumps([{
|
||||||
|
'name': b'one\xc3\xa9'.decode('utf8')}, ])),
|
||||||
Response(200, json.dumps([{'name': 'two'}, ])),
|
Response(200, json.dumps([{'name': 'two'}, ])),
|
||||||
Response(204, ''),
|
Response(204, ''),
|
||||||
]
|
]
|
||||||
@@ -779,13 +785,13 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
for item in client._iter_items('/', marker='start', end_marker='end'):
|
for item in client._iter_items('/', marker='start', end_marker='end'):
|
||||||
items.append(item['name'].encode('utf8'))
|
items.append(item['name'].encode('utf8'))
|
||||||
|
|
||||||
self.assertEqual('one\xc3\xa9 two'.split(), items)
|
self.assertEqual(b'one\xc3\xa9 two'.split(), items)
|
||||||
|
|
||||||
def test_iter_items_with_markers_and_prefix(self):
|
def test_iter_items_with_markers_and_prefix(self):
|
||||||
class Response(object):
|
class Response(object):
|
||||||
def __init__(self, status_int, body):
|
def __init__(self, status_int, body):
|
||||||
self.status_int = status_int
|
self.status_int = status_int
|
||||||
self.body = body
|
self.body = body.encode('ascii')
|
||||||
|
|
||||||
class InternalClient(internal_client.InternalClient):
|
class InternalClient(internal_client.InternalClient):
|
||||||
def __init__(self, test, paths, responses):
|
def __init__(self, test, paths, responses):
|
||||||
@@ -810,7 +816,8 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
responses = [
|
responses = [
|
||||||
Response(200, json.dumps([{'name': 'prefixed_one\xc3\xa9'}, ])),
|
Response(200, json.dumps([{
|
||||||
|
'name': b'prefixed_one\xc3\xa9'.decode('utf8')}, ])),
|
||||||
Response(200, json.dumps([{'name': 'prefixed_two'}, ])),
|
Response(200, json.dumps([{'name': 'prefixed_two'}, ])),
|
||||||
Response(204, ''),
|
Response(204, ''),
|
||||||
]
|
]
|
||||||
@@ -822,7 +829,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
prefix='prefixed_'):
|
prefix='prefixed_'):
|
||||||
items.append(item['name'].encode('utf8'))
|
items.append(item['name'].encode('utf8'))
|
||||||
|
|
||||||
self.assertEqual('prefixed_one\xc3\xa9 prefixed_two'.split(), items)
|
self.assertEqual(b'prefixed_one\xc3\xa9 prefixed_two'.split(), items)
|
||||||
|
|
||||||
def test_iter_item_read_response_if_status_is_acceptable(self):
|
def test_iter_item_read_response_if_status_is_acceptable(self):
|
||||||
class Response(object):
|
class Response(object):
|
||||||
@@ -851,11 +858,12 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
|
|
||||||
def generate_resp_body():
|
def generate_resp_body():
|
||||||
for i in range(1, 5):
|
for i in range(1, 5):
|
||||||
yield str(i)
|
yield str(i).encode('ascii')
|
||||||
num_list.append(i)
|
num_list.append(i)
|
||||||
|
|
||||||
exp_items = []
|
exp_items = []
|
||||||
responses = [Response(204, json.dumps([]), generate_resp_body())]
|
responses = [Response(204, json.dumps([]).encode('ascii'),
|
||||||
|
generate_resp_body())]
|
||||||
items = []
|
items = []
|
||||||
client = InternalClient(self, responses)
|
client = InternalClient(self, responses)
|
||||||
for item in client._iter_items('/'):
|
for item in client._iter_items('/'):
|
||||||
@@ -863,13 +871,15 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.assertEqual(exp_items, items)
|
self.assertEqual(exp_items, items)
|
||||||
self.assertEqual(len(num_list), 0)
|
self.assertEqual(len(num_list), 0)
|
||||||
|
|
||||||
responses = [Response(300, json.dumps([]), generate_resp_body())]
|
responses = [Response(300, json.dumps([]).encode('ascii'),
|
||||||
|
generate_resp_body())]
|
||||||
client = InternalClient(self, responses)
|
client = InternalClient(self, responses)
|
||||||
self.assertRaises(internal_client.UnexpectedResponse,
|
self.assertRaises(internal_client.UnexpectedResponse,
|
||||||
next, client._iter_items('/'))
|
next, client._iter_items('/'))
|
||||||
|
|
||||||
exp_items = []
|
exp_items = []
|
||||||
responses = [Response(404, json.dumps([]), generate_resp_body())]
|
responses = [Response(404, json.dumps([]).encode('ascii'),
|
||||||
|
generate_resp_body())]
|
||||||
items = []
|
items = []
|
||||||
client = InternalClient(self, responses)
|
client = InternalClient(self, responses)
|
||||||
for item in client._iter_items('/'):
|
for item in client._iter_items('/'):
|
||||||
@@ -1211,7 +1221,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
path_info = make_path_info(account, container, obj)
|
path_info = make_path_info(account, container, obj)
|
||||||
client, app = get_client_app()
|
client, app = get_client_app()
|
||||||
headers = {'foo': 'bar'}
|
headers = {'foo': 'bar'}
|
||||||
body = 'some_object_body'
|
body = b'some_object_body'
|
||||||
params = {'symlink': 'get'}
|
params = {'symlink': 'get'}
|
||||||
app.register('GET', path_info, swob.HTTPOk, headers, body)
|
app.register('GET', path_info, swob.HTTPOk, headers, body)
|
||||||
req_headers = {'x-important-header': 'some_important_value'}
|
req_headers = {'x-important-header': 'some_important_value'}
|
||||||
@@ -1220,7 +1230,7 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
self.assertEqual(status_int // 100, 2)
|
self.assertEqual(status_int // 100, 2)
|
||||||
for k, v in headers.items():
|
for k, v in headers.items():
|
||||||
self.assertEqual(v, resp_headers[k])
|
self.assertEqual(v, resp_headers[k])
|
||||||
self.assertEqual(''.join(obj_iter), body)
|
self.assertEqual(b''.join(obj_iter), body)
|
||||||
self.assertEqual(resp_headers['content-length'], str(len(body)))
|
self.assertEqual(resp_headers['content-length'], str(len(body)))
|
||||||
self.assertEqual(app.call_count, 1)
|
self.assertEqual(app.call_count, 1)
|
||||||
req_headers.update({
|
req_headers.update({
|
||||||
@@ -1240,9 +1250,9 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
|
|
||||||
def fake_app(self, env, start_response):
|
def fake_app(self, env, start_response):
|
||||||
start_response('200 Ok', [('Content-Length', '0')])
|
start_response('200 Ok', [('Content-Length', '0')])
|
||||||
return ['%s\n' % x for x in self.lines]
|
return [b'%s\n' % x for x in self.lines]
|
||||||
|
|
||||||
lines = 'line1 line2 line3'.split()
|
lines = b'line1 line2 line3'.split()
|
||||||
client = InternalClient(lines)
|
client = InternalClient(lines)
|
||||||
ret_lines = []
|
ret_lines = []
|
||||||
for line in client.iter_object_lines('account', 'container', 'object'):
|
for line in client.iter_object_lines('account', 'container', 'object'):
|
||||||
@@ -1260,9 +1270,9 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
def fake_app(self, env, start_response):
|
def fake_app(self, env, start_response):
|
||||||
start_response('200 Ok', [('Content-Length', '0')])
|
start_response('200 Ok', [('Content-Length', '0')])
|
||||||
return internal_client.CompressingFileReader(
|
return internal_client.CompressingFileReader(
|
||||||
StringIO('\n'.join(self.lines)))
|
BytesIO(b'\n'.join(self.lines)))
|
||||||
|
|
||||||
lines = 'line1 line2 line3'.split()
|
lines = b'line1 line2 line3'.split()
|
||||||
client = InternalClient(lines)
|
client = InternalClient(lines)
|
||||||
ret_lines = []
|
ret_lines = []
|
||||||
for line in client.iter_object_lines(
|
for line in client.iter_object_lines(
|
||||||
@@ -1359,8 +1369,8 @@ class TestInternalClient(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestGetAuth(unittest.TestCase):
|
class TestGetAuth(unittest.TestCase):
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
@mock.patch('eventlet.green.urllib2.Request')
|
@mock.patch.object(urllib2, 'Request')
|
||||||
def test_ok(self, request, urlopen):
|
def test_ok(self, request, urlopen):
|
||||||
def getheader(name):
|
def getheader(name):
|
||||||
d = {'X-Storage-Url': 'url', 'X-Auth-Token': 'token'}
|
d = {'X-Storage-Url': 'url', 'X-Auth-Token': 'token'}
|
||||||
@@ -1395,7 +1405,7 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
with mock.patch('swift.common.internal_client.time', mock_time):
|
with mock.patch('swift.common.internal_client.time', mock_time):
|
||||||
# basic request, only url as kwarg
|
# basic request, only url as kwarg
|
||||||
request.return_value.get_type.return_value = "http"
|
request.return_value.get_type.return_value = "http"
|
||||||
urlopen.return_value.read.return_value = ''
|
urlopen.return_value.read.return_value = b''
|
||||||
urlopen.return_value.getcode.return_value = 200
|
urlopen.return_value.getcode.return_value = 200
|
||||||
urlopen.return_value.info.return_value = {'content-length': '345'}
|
urlopen.return_value.info.return_value = {'content-length': '345'}
|
||||||
sc = internal_client.SimpleClient(url='http://127.0.0.1')
|
sc = internal_client.SimpleClient(url='http://127.0.0.1')
|
||||||
@@ -1414,7 +1424,7 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
'123 345 1401224050.98 1401224051.98 1.0 -',), {})])
|
'123 345 1401224050.98 1401224051.98 1.0 -',), {})])
|
||||||
|
|
||||||
# Check if JSON is decoded
|
# Check if JSON is decoded
|
||||||
urlopen.return_value.read.return_value = '{}'
|
urlopen.return_value.read.return_value = b'{}'
|
||||||
retval = sc.retry_request(method)
|
retval = sc.retry_request(method)
|
||||||
self.assertEqual([{'content-length': '345'}, {}], retval)
|
self.assertEqual([{'content-length': '345'}, {}], retval)
|
||||||
|
|
||||||
@@ -1450,18 +1460,18 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
data=None)
|
data=None)
|
||||||
self.assertEqual([{'content-length': '345'}, {}], retval)
|
self.assertEqual([{'content-length': '345'}, {}], retval)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
@mock.patch('eventlet.green.urllib2.Request')
|
@mock.patch.object(urllib2, 'Request')
|
||||||
def test_get(self, request, urlopen):
|
def test_get(self, request, urlopen):
|
||||||
self._test_get_head(request, urlopen, 'GET')
|
self._test_get_head(request, urlopen, 'GET')
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
@mock.patch('eventlet.green.urllib2.Request')
|
@mock.patch.object(urllib2, 'Request')
|
||||||
def test_head(self, request, urlopen):
|
def test_head(self, request, urlopen):
|
||||||
self._test_get_head(request, urlopen, 'HEAD')
|
self._test_get_head(request, urlopen, 'HEAD')
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
@mock.patch('eventlet.green.urllib2.Request')
|
@mock.patch.object(urllib2, 'Request')
|
||||||
def test_get_with_retries_all_failed(self, request, urlopen):
|
def test_get_with_retries_all_failed(self, request, urlopen):
|
||||||
# Simulate a failing request, ensure retries done
|
# Simulate a failing request, ensure retries done
|
||||||
request.return_value.get_type.return_value = "http"
|
request.return_value.get_type.return_value = "http"
|
||||||
@@ -1473,13 +1483,13 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(request.call_count, 2)
|
self.assertEqual(request.call_count, 2)
|
||||||
self.assertEqual(urlopen.call_count, 2)
|
self.assertEqual(urlopen.call_count, 2)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
@mock.patch('eventlet.green.urllib2.Request')
|
@mock.patch.object(urllib2, 'Request')
|
||||||
def test_get_with_retries(self, request, urlopen):
|
def test_get_with_retries(self, request, urlopen):
|
||||||
# First request fails, retry successful
|
# First request fails, retry successful
|
||||||
request.return_value.get_type.return_value = "http"
|
request.return_value.get_type.return_value = "http"
|
||||||
mock_resp = mock.MagicMock()
|
mock_resp = mock.MagicMock()
|
||||||
mock_resp.read.return_value = ''
|
mock_resp.read.return_value = b''
|
||||||
mock_resp.info.return_value = {}
|
mock_resp.info.return_value = {}
|
||||||
urlopen.side_effect = [urllib2.URLError(''), mock_resp]
|
urlopen.side_effect = [urllib2.URLError(''), mock_resp]
|
||||||
sc = internal_client.SimpleClient(url='http://127.0.0.1', retries=1,
|
sc = internal_client.SimpleClient(url='http://127.0.0.1', retries=1,
|
||||||
@@ -1495,10 +1505,10 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual([{}, None], retval)
|
self.assertEqual([{}, None], retval)
|
||||||
self.assertEqual(sc.attempts, 2)
|
self.assertEqual(sc.attempts, 2)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
def test_get_with_retries_param(self, mock_urlopen):
|
def test_get_with_retries_param(self, mock_urlopen):
|
||||||
mock_response = mock.MagicMock()
|
mock_response = mock.MagicMock()
|
||||||
mock_response.read.return_value = ''
|
mock_response.read.return_value = b''
|
||||||
mock_response.info.return_value = {}
|
mock_response.info.return_value = {}
|
||||||
mock_urlopen.side_effect = internal_client.httplib.BadStatusLine('')
|
mock_urlopen.side_effect = internal_client.httplib.BadStatusLine('')
|
||||||
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
||||||
@@ -1527,10 +1537,10 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(mock_urlopen.call_count, 2)
|
self.assertEqual(mock_urlopen.call_count, 2)
|
||||||
self.assertEqual([{}, None], retval)
|
self.assertEqual([{}, None], retval)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
def test_request_with_retries_with_HTTPError(self, mock_urlopen):
|
def test_request_with_retries_with_HTTPError(self, mock_urlopen):
|
||||||
mock_response = mock.MagicMock()
|
mock_response = mock.MagicMock()
|
||||||
mock_response.read.return_value = ''
|
mock_response.read.return_value = b''
|
||||||
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
||||||
self.assertEqual(c.retries, 5)
|
self.assertEqual(c.retries, 5)
|
||||||
|
|
||||||
@@ -1544,11 +1554,11 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(mock_sleep.call_count, 1)
|
self.assertEqual(mock_sleep.call_count, 1)
|
||||||
self.assertEqual(mock_urlopen.call_count, 2)
|
self.assertEqual(mock_urlopen.call_count, 2)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
def test_request_container_with_retries_with_HTTPError(self,
|
def test_request_container_with_retries_with_HTTPError(self,
|
||||||
mock_urlopen):
|
mock_urlopen):
|
||||||
mock_response = mock.MagicMock()
|
mock_response = mock.MagicMock()
|
||||||
mock_response.read.return_value = ''
|
mock_response.read.return_value = b''
|
||||||
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
||||||
self.assertEqual(c.retries, 5)
|
self.assertEqual(c.retries, 5)
|
||||||
|
|
||||||
@@ -1563,11 +1573,11 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(mock_sleep.call_count, 1)
|
self.assertEqual(mock_sleep.call_count, 1)
|
||||||
self.assertEqual(mock_urlopen.call_count, 2)
|
self.assertEqual(mock_urlopen.call_count, 2)
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch.object(urllib2, 'urlopen')
|
||||||
def test_request_object_with_retries_with_HTTPError(self,
|
def test_request_object_with_retries_with_HTTPError(self,
|
||||||
mock_urlopen):
|
mock_urlopen):
|
||||||
mock_response = mock.MagicMock()
|
mock_response = mock.MagicMock()
|
||||||
mock_response.read.return_value = ''
|
mock_response.read.return_value = b''
|
||||||
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
c = internal_client.SimpleClient(url='http://127.0.0.1', token='token')
|
||||||
self.assertEqual(c.retries, 5)
|
self.assertEqual(c.retries, 5)
|
||||||
|
|
||||||
@@ -1605,7 +1615,12 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(0.1, kwargs['timeout'])
|
self.assertEqual(0.1, kwargs['timeout'])
|
||||||
self.assertTrue(isinstance(args[0], urllib2.Request))
|
self.assertTrue(isinstance(args[0], urllib2.Request))
|
||||||
self.assertEqual(proxy_host, args[0].host)
|
self.assertEqual(proxy_host, args[0].host)
|
||||||
|
if six.PY2:
|
||||||
self.assertEqual(scheme, args[0].type)
|
self.assertEqual(scheme, args[0].type)
|
||||||
|
else:
|
||||||
|
# TODO: figure out why this happens, whether py2 or py3 is
|
||||||
|
# messed up, whether we care, and what can be done about it
|
||||||
|
self.assertEqual('https', args[0].type)
|
||||||
|
|
||||||
# class methods
|
# class methods
|
||||||
content = mock.MagicMock()
|
content = mock.MagicMock()
|
||||||
@@ -1625,7 +1640,11 @@ class TestSimpleClient(unittest.TestCase):
|
|||||||
self.assertEqual(0.1, kwargs['timeout'])
|
self.assertEqual(0.1, kwargs['timeout'])
|
||||||
self.assertTrue(isinstance(args[0], urllib2.Request))
|
self.assertTrue(isinstance(args[0], urllib2.Request))
|
||||||
self.assertEqual(proxy_host, args[0].host)
|
self.assertEqual(proxy_host, args[0].host)
|
||||||
|
if six.PY2:
|
||||||
self.assertEqual(scheme, args[0].type)
|
self.assertEqual(scheme, args[0].type)
|
||||||
|
else:
|
||||||
|
# See above
|
||||||
|
self.assertEqual('https', args[0].type)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
1
tox.ini
1
tox.ini
@@ -58,6 +58,7 @@ commands =
|
|||||||
test/unit/common/test_direct_client.py \
|
test/unit/common/test_direct_client.py \
|
||||||
test/unit/common/test_exceptions.py \
|
test/unit/common/test_exceptions.py \
|
||||||
test/unit/common/test_header_key_dict.py \
|
test/unit/common/test_header_key_dict.py \
|
||||||
|
test/unit/common/test_internal_client.py \
|
||||||
test/unit/common/test_linkat.py \
|
test/unit/common/test_linkat.py \
|
||||||
test/unit/common/test_manager.py \
|
test/unit/common/test_manager.py \
|
||||||
test/unit/common/test_memcached.py \
|
test/unit/common/test_memcached.py \
|
||||||
|
Reference in New Issue
Block a user