From 8f85e27c27302ae623e4c0811515858f8d340603 Mon Sep 17 00:00:00 2001 From: Alistair Coles Date: Fri, 18 Aug 2023 13:31:01 +0100 Subject: [PATCH] FakeSwift: use env['PATH_INFO'] to index uploaded objects Change-Id: If17e10d309826b815d2b5b470a8bff071f5c4e87 --- test/unit/common/middleware/helpers.py | 10 +- test/unit/common/middleware/test_helpers.py | 166 ++++++++++++-------- test/unit/common/middleware/test_slo.py | 18 +-- 3 files changed, 109 insertions(+), 85 deletions(-) diff --git a/test/unit/common/middleware/helpers.py b/test/unit/common/middleware/helpers.py index 14ff88b268..acb94c8bed 100644 --- a/test/unit/common/middleware/helpers.py +++ b/test/unit/common/middleware/helpers.py @@ -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: diff --git a/test/unit/common/middleware/test_helpers.py b/test/unit/common/middleware/test_helpers.py index e7b1892f84..cef4fac37f 100644 --- a/test/unit/common/middleware/test_helpers.py +++ b/test/unit/common/middleware/test_helpers.py @@ -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) diff --git a/test/unit/common/middleware/test_slo.py b/test/unit/common/middleware/test_slo.py index 8025158458..e85ad61318 100644 --- a/test/unit/common/middleware/test_slo.py +++ b/test/unit/common/middleware/test_slo.py @@ -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)