launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24912
[Merge] ~cjwatson/launchpad:py3-fakeswift into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:py3-fakeswift into launchpad:master.
Commit message:
Make the fake Swift fixture work on Python 3
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/386483
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-fakeswift into launchpad:master.
diff --git a/lib/lp/testing/swift/fakeswift.py b/lib/lp/testing/swift/fakeswift.py
index c90dc0d..e9eb5b7 100644
--- a/lib/lp/testing/swift/fakeswift.py
+++ b/lib/lp/testing/swift/fakeswift.py
@@ -110,27 +110,29 @@ class FakeKeystone(resource.Resource):
"""Validate provided credentials and return service catalog."""
if "application/json" not in request.getHeader('content-type'):
request.setResponseCode(http.BAD_REQUEST)
- return ""
- credentials = json.load(request.content)
+ return b""
+ # XXX cjwatson 2020-06-15: Python 3.5 doesn't allow this to be a
+ # binary file; 3.6 does.
+ credentials = json.loads(request.content.read().decode("UTF-8"))
if not "auth" in credentials:
request.setResponseCode(http.FORBIDDEN)
- return ""
+ return b""
if ((not "tenantName" in credentials["auth"] or
not "passwordCredentials" in credentials["auth"])):
request.setResponseCode(http.FORBIDDEN)
- return ""
+ return b""
tenant_name = credentials["auth"]["tenantName"]
pw_creds = credentials["auth"]["passwordCredentials"]
username, password = pw_creds.get("username"), pw_creds.get("password")
if not tenant_name in self.root.tenants:
request.setResponseCode(http.FORBIDDEN)
- return ""
+ return b""
if not username in self.users:
request.setResponseCode(http.FORBIDDEN)
- return ""
+ return b""
if password != DEFAULT_PASSWORD:
request.setResponseCode(http.FORBIDDEN)
- return ""
+ return b""
self.ensureValidToken(tenant_name)
@@ -142,7 +144,7 @@ class FakeKeystone(resource.Resource):
"token": self.getValidToken(tenant_name),
"user": self.getUser(username),
}
- })
+ }).encode("UTF-8")
def parse_range_header(range):
@@ -175,7 +177,7 @@ class EmptyPage(resource.Resource):
"""Return an empty document."""
isLeaf = True
- def __init__(self, retcode=http.OK, headers=None, body=""):
+ def __init__(self, retcode=http.OK, headers=None, body=b""):
resource.Resource.__init__(self)
self._retcode = retcode
self._headers = headers
@@ -252,9 +254,9 @@ class SwiftObject(resource.Resource):
request.setHeader("ETag", self._etag)
range = request.getHeader("Range")
size = len(self.contents)
- if request.method == 'HEAD':
+ if request.method == b'HEAD':
request.setHeader("Content-Length", str(size))
- return ""
+ return b""
if range:
ranges = parse_range_header(range)
length = 0
@@ -263,7 +265,7 @@ class SwiftObject(resource.Resource):
if begin is None:
request.setResponseCode(
http.REQUESTED_RANGE_NOT_SATISFIABLE)
- return ''
+ return b''
if not end:
end = size
elif end < size:
@@ -273,7 +275,7 @@ class SwiftObject(resource.Resource):
http.REQUESTED_RANGE_NOT_SATISFIABLE)
request.setHeader(
'content-range', 'bytes */%d' % size)
- return ''
+ return b''
else:
request.setHeader(
'content-range',
@@ -285,7 +287,7 @@ class SwiftObject(resource.Resource):
else:
# multiple ranges should be returned in a multipart response
request.setResponseCode(http.REQUESTED_RANGE_NOT_SATISFIABLE)
- return ''
+ return b''
else:
request.setHeader("Content-Length", str(size))
@@ -318,7 +320,7 @@ class SwiftObject(resource.Resource):
request.setHeader("ETag", self.get_etag())
logger.debug("created object container=%s name=%s size=%d" % (
self.container, self.name, len(data)))
- return ""
+ return b""
class SwiftContainer(resource.Resource):
@@ -351,18 +353,19 @@ class SwiftContainer(resource.Resource):
if name and request.postpath:
name = os.path.join(*((name,)+tuple(request.postpath)))
assert (name), "Wrong call stack for name='%s'" % (name,)
- if request.method == "PUT":
+ if request.method == b"PUT":
child = SwiftObject(self, name)
- elif request.method in ("GET", "HEAD") :
+ elif request.method in (b"GET", b"HEAD"):
child = self.container_children.get(name, None)
- elif request.method == "DELETE":
+ elif request.method == b"DELETE":
child = self.container_children.get(name, None)
if child is None: # delete unknown object
return EmptyPage(http.NO_CONTENT)
del self.container_children[name]
return EmptyPage(http.NO_CONTENT)
else:
- logger.error("UNHANDLED request method %s" % request.method)
+ logger.error(
+ "UNHANDLED request method %s" % request.method.decode("UTF-8"))
return EmptyPage(http.METHOD_NOT_ALLOWED)
if child is None:
return EmptyPage(http.NOT_FOUND)
@@ -370,25 +373,25 @@ class SwiftContainer(resource.Resource):
def render_GET(self, request):
"""Return list of keys in response to GET on container."""
- if request.args.get('format', [])[0] != "json":
+ if request.args.get(b'format', [])[0] != b"json":
raise NotImplementedError()
results = []
- marker = request.args.get('marker', [None])[0]
- end_marker = request.args.get('end_marker', [None])[0]
- prefix = request.args.get('prefix', [None])[0]
- format_ = request.args.get('format', [None])[0]
- delimiter = request.args.get('delimiter', None)
- path = request.args.get('path', None)
-
- if format_ != 'json' or delimiter or path:
+ marker = request.args.get(b'marker', [None])[0]
+ end_marker = request.args.get(b'end_marker', [None])[0]
+ prefix = request.args.get(b'prefix', [None])[0]
+ format_ = request.args.get(b'format', [None])[0]
+ delimiter = request.args.get(b'delimiter', None)
+ path = request.args.get(b'path', None)
+
+ if format_ != b'json' or delimiter or path:
raise NotImplementedError()
# According to the docs, limit will be 10000 if no query
# parameters are passed. However, as we require at least the
# 'format' query parameter above, the default is always
# unlimited.
- limit = int(request.args.get('limit', [sys.maxint])[0])
+ limit = int(request.args.get(b'limit', [2 ** 31 - 1])[0])
results = []
for name, child in sorted(self.iter_children()):
@@ -407,14 +410,14 @@ class SwiftContainer(resource.Resource):
'%Y-%m-%dT%H:%M:%S.%f')
results.append({
- 'name': name,
+ 'name': name.decode('UTF-8'),
'bytes': child.get_size(),
'hash': child._etag,
'content-type': child.content_type,
'last_modified': mod_time,
})
- return json.dumps(results)
+ return json.dumps(results).encode('UTF-8')
class FakeContent(io.IOBase):
@@ -461,7 +464,7 @@ class SizeContainer(SwiftContainer):
def getChild(self, name, request):
"""Get the next object down the chain."""
try:
- fake = FakeContent("0", int(name))
+ fake = FakeContent(b"0", int(name))
o = SwiftObject(self, name, fake, "text/plain", fake.hexdigest())
return o
except ValueError:
@@ -475,7 +478,7 @@ class FakeSwift(resource.Resource):
resource.Resource.__init__(self)
self.root = root
self.containers = {
- "size": SizeContainer("size", DEFAULT_TENANT_NAME),
+ b"size": SizeContainer(b"size", DEFAULT_TENANT_NAME),
}
def addContainer(self, name):
@@ -492,24 +495,24 @@ class FakeSwift(resource.Resource):
# if we operate on a key, pass control
if (((request.postpath and request.postpath[0]) or
- (not request.postpath and request.method == "GET"))):
+ (not request.postpath and request.method == b"GET"))):
if container is None:
# container does not exist, yet we attempt operation on
# an object from that container
return EmptyPage(http.NOT_FOUND)
return container
- if request.method == "HEAD":
+ if request.method == b"HEAD":
if container is None:
return EmptyPage(http.NOT_FOUND)
return EmptyPage(http.NO_CONTENT)
- if request.method == "PUT":
+ if request.method == b"PUT":
if container is None:
container = self.addContainer(name)
return EmptyPage()
- if request.method == "DELETE":
+ if request.method == b"DELETE":
if container is None: # delete unknown object
return EmptyPage(http.NO_CONTENT)
del self.containers[name]
diff --git a/lib/lp/testing/swift/tests/test_fixture.py b/lib/lp/testing/swift/tests/test_fixture.py
index e3a5a31..234a80f 100644
--- a/lib/lp/testing/swift/tests/test_fixture.py
+++ b/lib/lp/testing/swift/tests/test_fixture.py
@@ -37,8 +37,8 @@ class TestSwiftFixture(TestCase):
def makeSampleObject(self, client, contents, content_type=None):
"""Create a new container and a new sample object within it."""
- cname = self.factory.getUniqueString()
- oname = self.factory.getUniqueString()
+ cname = self.factory.getUniqueUnicode()
+ oname = self.factory.getUniqueUnicode()
client.put_container(cname)
client.put_object(cname, oname, contents, content_type=content_type)
return cname, oname
@@ -47,13 +47,13 @@ class TestSwiftFixture(TestCase):
client = self.swift_fixture.connect()
size = 30
headers, body = client.get_object("size", str(size))
- self.assertEqual("0" * size, body)
+ self.assertEqual(b"0" * size, body)
self.assertEqual(str(size), headers["content-length"])
self.assertEqual("text/plain", headers["content-type"])
def test_get_404(self):
client = self.swift_fixture.connect()
- cname = self.factory.getUniqueString()
+ cname = self.factory.getUniqueUnicode()
client.put_container(cname)
exc = self.assertRaises(
swiftclient.ClientException,
@@ -72,7 +72,7 @@ class TestSwiftFixture(TestCase):
def test_put(self):
client = self.swift_fixture.connect()
- message = "Hello World!"
+ message = b"Hello World!"
cname, oname = self.makeSampleObject(client, message, "text/something")
for x in range(1, 10):
headers, body = client.get_object(cname, oname)
@@ -86,7 +86,7 @@ class TestSwiftFixture(TestCase):
# Basic container listing.
start = datetime.utcnow().replace(microsecond=0)
client = self.swift_fixture.connect()
- message = "42"
+ message = b"42"
cname, oname = self.makeSampleObject(client, message, "text/something")
client.put_object(cname, oname + ".2", message)
@@ -105,7 +105,7 @@ class TestSwiftFixture(TestCase):
def test_get_container_marker(self):
# Container listing supports the marker parameter.
client = self.swift_fixture.connect()
- message = "Hello"
+ message = b"Hello"
cname, oname = self.makeSampleObject(client, message, "text/something")
oname2 = oname + ".2"
oname3 = oname + ".3"
@@ -121,7 +121,7 @@ class TestSwiftFixture(TestCase):
def test_get_container_end_marker(self):
# Container listing supports the end_marker parameter.
client = self.swift_fixture.connect()
- message = "Hello"
+ message = b"Hello"
cname, oname = self.makeSampleObject(client, message, "text/something")
oname2 = oname + ".2"
oname3 = oname + ".3"
@@ -137,7 +137,7 @@ class TestSwiftFixture(TestCase):
def test_get_container_limit(self):
# Container listing supports the limit parameter.
client = self.swift_fixture.connect()
- message = "Hello"
+ message = b"Hello"
cname, oname = self.makeSampleObject(client, message, "text/something")
oname2 = oname + ".2"
oname3 = oname + ".3"
@@ -152,7 +152,7 @@ class TestSwiftFixture(TestCase):
def test_get_container_prefix(self):
client = self.swift_fixture.connect()
- message = "Hello"
+ message = b"Hello"
cname, oname = self.makeSampleObject(client, message, "text/something")
oname2 = "different"
oname3 = oname + ".3"
@@ -167,7 +167,7 @@ class TestSwiftFixture(TestCase):
def test_get_container_full_listing(self):
client = self.swift_fixture.connect()
- message = "42"
+ message = b"42"
cname, oname = self.makeSampleObject(client, message, "text/something")
_, container = client.get_container(cname, full_listing=True)
@@ -194,7 +194,7 @@ class TestSwiftFixture(TestCase):
# Things work fine when the Swift server is up.
self.swift_fixture.startup()
headers, body = client.get_object("size", str(size))
- self.assertEqual(body, "0" * size)
+ self.assertEqual(body, b"0" * size)
# But if the Swift server goes away again, we end up with
# different failures since the connection has already
@@ -214,7 +214,7 @@ class TestSwiftFixture(TestCase):
# But fresh connections are fine.
client = self.swift_fixture.connect()
headers, body = client.get_object("size", str(size))
- self.assertEqual(body, "0" * size)
+ self.assertEqual(body, b"0" * size)
def test_env(self):
self.assertEqual(