FakeSwift: use env['PATH_INFO'] to index uploaded objects

Change-Id: If17e10d309826b815d2b5b470a8bff071f5c4e87
This commit is contained in:
Alistair Coles 2023-08-18 13:31:01 +01:00
parent 746daad337
commit 8f85e27c27
3 changed files with 109 additions and 85 deletions

View File

@ -178,9 +178,9 @@ class FakeSwift(object):
else:
# special case for re-reading an uploaded file
# ... uploaded is only objects and always raw path
if method in ('GET', 'HEAD') and path in self.uploaded:
if method in ('GET', 'HEAD') and env['PATH_INFO'] in self.uploaded:
resp_class = swob.HTTPOk
headers, body = self.uploaded[path]
headers, body = self.uploaded[env['PATH_INFO']]
else:
raise KeyError("Didn't find %r in allowed responses" % (
(method, path),))
@ -242,11 +242,11 @@ class FakeSwift(object):
resp_headers = dict(req.headers)
if "CONTENT_TYPE" in env:
resp_headers['Content-Type'] = env["CONTENT_TYPE"]
self.uploaded[path] = (resp_headers, req_body)
self.uploaded[env['PATH_INFO']] = (resp_headers, req_body)
# simulate object POST
elif method == 'POST' and obj:
metadata, data = self.uploaded.get(path, ({}, None))
metadata, data = self.uploaded.get(env['PATH_INFO'], ({}, None))
# select items to keep from existing...
new_metadata = dict(
(k, v) for k, v in metadata.items()
@ -258,7 +258,7 @@ class FakeSwift(object):
if (is_user_meta('object', k) or
is_object_transient_sysmeta(k) or
k.lower == 'content-type')))
self.uploaded[path] = new_metadata, data
self.uploaded[env['PATH_INFO']] = new_metadata, data
# simulate object GET/HEAD
elif method in ('GET', 'HEAD') and obj:

View File

@ -153,7 +153,8 @@ class TestFakeSwift(unittest.TestCase):
self.assertEqual(('HEAD', '/v1/a/c/o?p=q'), swift.calls[-1])
def test_PUT_uploaded(self):
# verify an uploaded object is sufficient to handle GETs and HEADS
# verify an uploaded object is sufficient to handle GETs and HEADS,
# with and without query strings
swift = FakeSwift()
swift.register('PUT', '/v1/a/c/o', HTTPCreated, {}, None)
req = Request.blank('/v1/a/c/o', body=b'stuff')
@ -180,6 +181,19 @@ class TestFakeSwift(unittest.TestCase):
self.assertEqual(2, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
req.query_string = 'p=q'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'stuff', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o?p=q'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'HEAD'
resp = req.get_response(swift)
@ -189,18 +203,25 @@ class TestFakeSwift(unittest.TestCase):
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(4, swift.call_count)
self.assertEqual(('HEAD', '/v1/a/c/o'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
req.method = 'HEAD'
req.query_string = 'p=q'
with self.assertRaises(KeyError):
resp = req.get_response(swift)
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(5, swift.call_count)
self.assertEqual(('HEAD', '/v1/a/c/o?p=q'), swift.calls[-1])
def test_PUT_uploaded_with_query_string(self):
# verify an uploaded object with query string is sufficient to handle
# GETs and HEADS
# GETs and HEADS, with and without query strings
swift = FakeSwift()
swift.register('PUT', '/v1/a/c/o', HTTPCreated, {}, None)
req = Request.blank('/v1/a/c/o', body=b'stuff')
@ -218,19 +239,13 @@ class TestFakeSwift(unittest.TestCase):
swift.calls[-1])
# note: query string is not included in uploaded key
self.assertEqual(
{'/v1/a/c/o?multipart-manifest=put': ({'Host': 'localhost:80',
'Content-Length': '5'},
b'stuff')},
{'/v1/a/c/o': ({'Host': 'localhost:80',
'Content-Length': '5'},
b'stuff')},
swift.uploaded)
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
with self.assertRaises(KeyError):
resp = req.get_response(swift)
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
req.query_string = 'multipart-manifest=put'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
@ -239,12 +254,23 @@ class TestFakeSwift(unittest.TestCase):
resp.headers)
self.assertEqual(b'stuff', resp.body)
self.assertEqual(2, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o?multipart-manifest=put'),
swift.calls[-1])
self.assertEqual(('GET', '/v1/a/c/o'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
req.query_string = 'p=q' # note: differs from PUT query string
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'stuff', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o?p=q'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'HEAD'
req.query_string = 'multipart-manifest=put'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
@ -252,14 +278,21 @@ class TestFakeSwift(unittest.TestCase):
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(('HEAD', '/v1/a/c/o?multipart-manifest=put'),
swift.calls[-1])
self.assertEqual(4, swift.call_count)
self.assertEqual(('HEAD', '/v1/a/c/o'), swift.calls[-1])
req = Request.blank('/v1/a/c/o')
req.method = 'HEAD'
with self.assertRaises(KeyError):
resp = req.get_response(swift)
req.query_string = 'p=q'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(5, swift.call_count)
self.assertEqual(('HEAD', '/v1/a/c/o?p=q'), swift.calls[-1])
def test_PUT_POST(self):
# verify an uploaded object is updated by a POST
@ -323,47 +356,15 @@ class TestFakeSwift(unittest.TestCase):
self.assertEqual(b'', resp.body)
self.assertEqual(1, swift.call_count)
self.assertEqual(('PUT', '/v1/a/c/o?p=q'), swift.calls[-1])
# note: query string is not included in uploaded key
self.assertEqual(
{'/v1/a/c/o?p=q': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Bar'},
b'stuff')},
{'/v1/a/c/o': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Bar'},
b'stuff')},
swift.uploaded)
# POST with query string should update the uploaded object
req = Request.blank('/v1/a/c/o', body=b'stuff',
headers={'X-Object-Meta-Foo': 'Bof'})
req.method = 'POST'
req.query_string = 'p=q'
resp = req.get_response(swift)
self.assertEqual(201, resp.status_int)
self.assertEqual({'Content-Type': 'text/html; charset=UTF-8'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(2, swift.call_count)
self.assertEqual(('POST', '/v1/a/c/o?p=q'), swift.calls[-1])
self.assertEqual(
{'/v1/a/c/o?p=q': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Bof'},
b'stuff')},
swift.uploaded)
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
req.query_string = 'p=q'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80',
'X-Object-Meta-Foo': 'Bof'},
resp.headers)
self.assertEqual(b'stuff', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o?p=q'), swift.calls[-1])
# POST without query string doesn't match
# POST without query string should update the uploaded object
req = Request.blank('/v1/a/c/o', body=b'stuff',
headers={'X-Object-Meta-Foo': 'Baz'})
req.method = 'POST'
@ -372,16 +373,47 @@ class TestFakeSwift(unittest.TestCase):
self.assertEqual({'Content-Type': 'text/html; charset=UTF-8'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(4, swift.call_count)
self.assertEqual(2, swift.call_count)
self.assertEqual(('POST', '/v1/a/c/o'), swift.calls[-1])
self.assertEqual(
{'/v1/a/c/o?p=q': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Bof'},
b'stuff'),
'/v1/a/c/o': ({'X-Object-Meta-Foo': 'Baz'}, None)},
{'/v1/a/c/o': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Baz'},
b'stuff')},
swift.uploaded)
# POST with different query string should update the uploaded object
req = Request.blank('/v1/a/c/o', body=b'stuff',
headers={'X-Object-Meta-Foo': 'Bof'})
req.method = 'POST'
req.query_string = 'x=y'
resp = req.get_response(swift)
self.assertEqual(201, resp.status_int)
self.assertEqual({'Content-Type': 'text/html; charset=UTF-8'},
resp.headers)
self.assertEqual(b'', resp.body)
self.assertEqual(3, swift.call_count)
self.assertEqual(('POST', '/v1/a/c/o?x=y'), swift.calls[-1])
self.assertEqual(
{'/v1/a/c/o': ({'Host': 'localhost:80',
'Content-Length': '5',
'X-Object-Meta-Foo': 'Bof'},
b'stuff')},
swift.uploaded)
req = Request.blank('/v1/a/c/o')
req.method = 'GET'
resp = req.get_response(swift)
self.assertEqual(200, resp.status_int)
self.assertEqual({'Content-Length': '5',
'Content-Type': 'text/html; charset=UTF-8',
'Host': 'localhost:80',
'X-Object-Meta-Foo': 'Bof'},
resp.headers)
self.assertEqual(b'stuff', resp.body)
self.assertEqual(4, swift.call_count)
self.assertEqual(('GET', '/v1/a/c/o'), swift.calls[-1])
def test_GET_registered_overrides_uploaded(self):
swift = FakeSwift()
swift.register('PUT', '/v1/a/c/o', HTTPCreated, {}, None)

View File

@ -849,9 +849,7 @@ class TestSloPutManifest(SloTestCase):
# go behind SLO's back and see what actually got stored
req = Request.blank(
# this string looks weird, but it's just an artifact
# of FakeSwift
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
'/v1/AUTH_test/checktest/man_3?multipart-manifest=get',
environ={'REQUEST_METHOD': 'GET'})
status, headers, body = self.call_app(req)
headers = dict(headers)
@ -903,9 +901,7 @@ class TestSloPutManifest(SloTestCase):
# Check that we still populated the manifest properly from our HEADs
req = Request.blank(
# this string looks weird, but it's just an artifact
# of FakeSwift
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
'/v1/AUTH_test/checktest/man_3?multipart-manifest=get',
environ={'REQUEST_METHOD': 'GET'})
status, headers, body = self.call_app(req)
manifest_data = json.loads(body)
@ -956,9 +952,7 @@ class TestSloPutManifest(SloTestCase):
# Check that we still populated the manifest properly from our HEADs
req = Request.blank(
# this string looks weird, but it's just an artifact
# of FakeSwift
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
'/v1/AUTH_test/checktest/man_3?multipart-manifest=get',
environ={'REQUEST_METHOD': 'GET'})
status, headers, body = self.call_app(req)
manifest_data = json.loads(body)
@ -983,7 +977,7 @@ class TestSloPutManifest(SloTestCase):
# Check that we still populated the manifest properly from our HEADs
req = Request.blank(
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
'/v1/AUTH_test/checktest/man_3?multipart-manifest=get',
environ={'REQUEST_METHOD': 'GET'})
status, headers, body = self.call_app(req)
manifest_data = json.loads(body)
@ -1085,9 +1079,7 @@ class TestSloPutManifest(SloTestCase):
# Check that we still populated the manifest properly from our HEADs
req = Request.blank(
# this string looks weird, but it's just an artifact
# of FakeSwift
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
'/v1/AUTH_test/checktest/man_3?multipart-manifest=get',
environ={'REQUEST_METHOD': 'GET'})
status, headers, body = self.call_app(req)
manifest_data = json.loads(body)