From 432e280aef1ba08bbb8dc239260604024325c9f6 Mon Sep 17 00:00:00 2001 From: Timur Alperovich Date: Wed, 15 Jul 2015 14:22:45 -0700 Subject: [PATCH] Correctly handle keys starting with the delimiter. When processing keys where the names start with the delimiter character, swift should list only the delimiter character. To get the list of nested keys, the caller should also supply the prefix which is equal to the delimiter. Added a functional test and unit tests to verify this behavior. Fixes Bug: 1475018 Change-Id: I27701a31bfa22842c272b7781738e8c546b82cbc --- swift/container/backend.py | 2 +- test/functional/tests.py | 14 ++++++++++++++ test/unit/container/test_backend.py | 3 +++ test/unit/container/test_server.py | 24 ++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/swift/container/backend.py b/swift/container/backend.py index 15155e252b..c3aac55723 100644 --- a/swift/container/backend.py +++ b/swift/container/backend.py @@ -674,7 +674,7 @@ class ContainerBroker(DatabaseBroker): marker = name[:end] + chr(ord(delimiter) + 1) curs.close() break - elif end > 0: + elif end >= 0: if reverse: end_marker = name[:end + 1] else: diff --git a/test/functional/tests.py b/test/functional/tests.py index fcc239c4c4..ad5437ad6d 100644 --- a/test/functional/tests.py +++ b/test/functional/tests.py @@ -610,6 +610,20 @@ class TestContainer(Base): 'reverse': 'yes'}) self.assertEqual(results, ['baza', 'bar']) + def testLeadingDelimiter(self): + cont = self.env.account.container(Utils.create_name()) + self.assertTrue(cont.create()) + + delimiter = '/' + files = ['test', delimiter.join(['', 'test', 'bar']), + delimiter.join(['', 'test', 'bar', 'foo'])] + for f in files: + file_item = cont.file(f) + self.assertTrue(file_item.write_random()) + + results = cont.files(parms={'delimiter': delimiter}) + self.assertEqual(results, [delimiter, 'test']) + def testCreate(self): cont = self.env.account.container(Utils.create_name()) self.assertTrue(cont.create()) diff --git a/test/unit/container/test_backend.py b/test/unit/container/test_backend.py index 721f0f9094..ab53ebf65c 100644 --- a/test/unit/container/test_backend.py +++ b/test/unit/container/test_backend.py @@ -1187,6 +1187,9 @@ class TestContainerBroker(unittest.TestCase): listing = broker.list_objects_iter(100, None, None, '/pets/fish/', '/') self.assertEqual([row[0] for row in listing], ['/pets/fish/a', '/pets/fish/b']) + listing = broker.list_objects_iter(100, None, None, None, '/') + self.assertEqual([row[0] for row in listing], + ['/']) def test_list_objects_iter_order_and_reverse(self): # Test ContainerBroker.list_objects_iter diff --git a/test/unit/container/test_server.py b/test/unit/container/test_server.py index fb414207d5..17a8ed085a 100644 --- a/test/unit/container/test_server.py +++ b/test/unit/container/test_server.py @@ -2093,6 +2093,30 @@ class TestContainerController(unittest.TestCase): {"subdir": "US-TX-"}, {"subdir": "US-UT-"}]) + def test_GET_leading_delimiter(self): + req = Request.blank( + '/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', + 'HTTP_X_TIMESTAMP': '0'}) + resp = req.get_response(self.controller) + for i in ('US-TX-A', 'US-TX-B', '-UK', '-CH'): + req = Request.blank( + '/sda1/p/a/c/%s' % i, + environ={ + 'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1', + 'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x', + 'HTTP_X_SIZE': 0}) + self._update_object_put_headers(req) + resp = req.get_response(self.controller) + self.assertEqual(resp.status_int, 201) + req = Request.blank( + '/sda1/p/a/c?delimiter=-&format=json', + environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.controller) + self.assertEqual( + json.loads(resp.body), + [{"subdir": "-"}, + {"subdir": "US-"}]) + def test_GET_delimiter_xml(self): req = Request.blank( '/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',