We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add regression test for datastore keys (object names) with / separator
See https://github.com/GoogleCloudPlatform/gcloud-python/pull/371#issuecomment-62659321


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `regression/storage.py`
Content:
```
1 from Crypto.Hash import MD5
2 import base64
3 import httplib2
4 import tempfile
5 import time
6 import unittest2
7 
8 from gcloud import storage
9 # This assumes the command is being run via tox hence the
10 # repository root is the current directory.
11 from regression import regression_utils
12 
13 
14 HTTP = httplib2.Http()
15 SHARED_BUCKETS = {}
16 
17 
18 def setUpModule():
19     if 'test_bucket' not in SHARED_BUCKETS:
20         connection = regression_utils.get_storage_connection()
21         # %d rounds milliseconds to nearest integer.
22         bucket_name = 'new%d' % (1000 * time.time(),)
23         # In the **very** rare case the bucket name is reserved, this
24         # fails with a ConnectionError.
25         SHARED_BUCKETS['test_bucket'] = connection.create_bucket(bucket_name)
26 
27 
28 def tearDownModule():
29     for bucket in SHARED_BUCKETS.values():
30         # Passing force=True also deletes all files.
31         bucket.delete(force=True)
32 
33 
34 class TestStorage(unittest2.TestCase):
35 
36     @classmethod
37     def setUpClass(cls):
38         cls.connection = regression_utils.get_storage_connection()
39 
40 
41 class TestStorageBuckets(TestStorage):
42 
43     def setUp(self):
44         self.case_buckets_to_delete = []
45 
46     def tearDown(self):
47         for bucket in self.case_buckets_to_delete:
48             bucket.delete()
49 
50     def test_create_bucket(self):
51         new_bucket_name = 'a-new-bucket'
52         self.assertRaises(storage.exceptions.NotFound,
53                           self.connection.get_bucket, new_bucket_name)
54         created = self.connection.create_bucket(new_bucket_name)
55         self.case_buckets_to_delete.append(created)
56         self.assertEqual(created.name, new_bucket_name)
57 
58     def test_get_buckets(self):
59         buckets_to_create = [
60             'new%d' % (1000 * time.time(),),
61             'newer%d' % (1000 * time.time(),),
62             'newest%d' % (1000 * time.time(),),
63         ]
64         created_buckets = []
65         for bucket_name in buckets_to_create:
66             bucket = self.connection.create_bucket(bucket_name)
67             self.case_buckets_to_delete.append(bucket)
68 
69         # Retrieve the buckets.
70         all_buckets = self.connection.get_all_buckets()
71         created_buckets = [bucket for bucket in all_buckets
72                            if bucket.name in buckets_to_create]
73         self.assertEqual(len(created_buckets), len(buckets_to_create))
74 
75 
76 class TestStorageFiles(TestStorage):
77 
78     FILES = {
79         'logo': {
80             'path': 'regression/data/CloudPlatform_128px_Retina.png',
81         },
82         'big': {
83             'path': 'regression/data/five-mb-file.zip',
84         },
85     }
86 
87     @staticmethod
88     def _get_base64_md5hash(filename):
89         with open(filename, 'rb') as file_obj:
90             hash = MD5.new(data=file_obj.read())
91         digest_bytes = hash.digest()
92         return base64.b64encode(digest_bytes)
93 
94     @classmethod
95     def setUpClass(cls):
96         super(TestStorageFiles, cls).setUpClass()
97         for file_data in cls.FILES.values():
98             file_data['hash'] = cls._get_base64_md5hash(file_data['path'])
99         cls.bucket = SHARED_BUCKETS['test_bucket']
100 
101     def setUp(self):
102         self.case_keys_to_delete = []
103 
104     def tearDown(self):
105         for key in self.case_keys_to_delete:
106             key.delete()
107 
108 
109 class TestStorageWriteFiles(TestStorageFiles):
110 
111     def test_large_file_write_from_stream(self):
112         key = self.bucket.new_key('LargeFile')
113         self.assertEqual(key._properties, {})
114 
115         file_data = self.FILES['big']
116         with open(file_data['path'], 'rb') as file_obj:
117             self.bucket.upload_file_object(file_obj, key=key)
118             self.case_keys_to_delete.append(key)
119 
120         key._properties.clear()  # force a reload
121         self.assertEqual(key.md5_hash, file_data['hash'])
122 
123     def test_write_metadata(self):
124         key = self.bucket.upload_file(self.FILES['logo']['path'])
125         self.case_keys_to_delete.append(key)
126 
127         # NOTE: This should not be necessary. We should be able to pass
128         #       it in to upload_file and also to upload_from_string.
129         key.content_type = 'image/png'
130         key._properties.clear()  # force a reload
131         self.assertEqual(key.content_type, 'image/png')
132 
133     def test_direct_write_and_read_into_file(self):
134         key = self.bucket.new_key('MyBuffer')
135         file_contents = 'Hello World'
136         key.upload_from_string(file_contents)
137         self.case_keys_to_delete.append(key)
138 
139         same_key = self.bucket.new_key('MyBuffer')
140         temp_filename = tempfile.mktemp()
141         with open(temp_filename, 'w') as file_obj:
142             same_key.get_contents_to_file(file_obj)
143 
144         with open(temp_filename, 'rb') as file_obj:
145             stored_contents = file_obj.read()
146 
147         self.assertEqual(file_contents, stored_contents)
148 
149     def test_copy_existing_file(self):
150         key = self.bucket.upload_file(self.FILES['logo']['path'],
151                                       key='CloudLogo')
152         self.case_keys_to_delete.append(key)
153 
154         new_key = self.bucket.copy_key(key, self.bucket, 'CloudLogoCopy')
155         self.case_keys_to_delete.append(new_key)
156 
157         base_contents = key.get_contents_as_string()
158         copied_contents = new_key.get_contents_as_string()
159         self.assertEqual(base_contents, copied_contents)
160 
161 
162 class TestStorageListFiles(TestStorageFiles):
163 
164     FILENAMES = ['CloudLogo1', 'CloudLogo2', 'CloudLogo3']
165 
166     @classmethod
167     def setUpClass(cls):
168         super(TestStorageListFiles, cls).setUpClass()
169         # Make sure bucket empty before beginning.
170         for key in cls.bucket:
171             key.delete()
172 
173         logo_path = cls.FILES['logo']['path']
174         key = cls.bucket.upload_file(logo_path, key=cls.FILENAMES[0])
175         cls.suite_keys_to_delete = [key]
176 
177         # Copy main key onto remaining in FILENAMES.
178         for filename in cls.FILENAMES[1:]:
179             new_key = cls.bucket.copy_key(key, cls.bucket, filename)
180             cls.suite_keys_to_delete.append(new_key)
181 
182     @classmethod
183     def tearDownClass(cls):
184         for key in cls.suite_keys_to_delete:
185             key.delete()
186 
187     def test_list_files(self):
188         all_keys = self.bucket.get_all_keys()
189         self.assertEqual(len(all_keys), len(self.FILENAMES))
190 
191     def test_paginate_files(self):
192         truncation_size = 1
193         count = len(self.FILENAMES) - truncation_size
194         iterator = self.bucket.iterator(max_results=count)
195         response = iterator.get_next_page_response()
196         keys = list(iterator.get_items_from_response(response))
197         self.assertEqual(len(keys), count)
198         self.assertEqual(iterator.page_number, 1)
199         self.assertTrue(iterator.next_page_token is not None)
200 
201         response = iterator.get_next_page_response()
202         last_keys = list(iterator.get_items_from_response(response))
203         self.assertEqual(len(last_keys), truncation_size)
204 
205 
206 class TestStorageSignURLs(TestStorageFiles):
207 
208     def setUp(self):
209         super(TestStorageSignURLs, self).setUp()
210 
211         logo_path = self.FILES['logo']['path']
212         with open(logo_path, 'r') as file_obj:
213             self.LOCAL_FILE = file_obj.read()
214 
215         key = self.bucket.new_key('LogoToSign.jpg')
216         key.upload_from_string(self.LOCAL_FILE)
217         self.case_keys_to_delete.append(key)
218 
219     def tearDown(self):
220         for key in self.case_keys_to_delete:
221             if key.exists():
222                 key.delete()
223 
224     def test_create_signed_read_url(self):
225         key = self.bucket.new_key('LogoToSign.jpg')
226         expiration = int(time.time() + 5)
227         signed_url = key.generate_signed_url(expiration, method='GET')
228 
229         response, content = HTTP.request(signed_url, method='GET')
230         self.assertEqual(response.status, 200)
231         self.assertEqual(content, self.LOCAL_FILE)
232 
233     def test_create_signed_delete_url(self):
234         key = self.bucket.new_key('LogoToSign.jpg')
235         expiration = int(time.time() + 283473274)
236         signed_delete_url = key.generate_signed_url(expiration,
237                                                     method='DELETE')
238 
239         response, content = HTTP.request(signed_delete_url, method='DELETE')
240         self.assertEqual(response.status, 204)
241         self.assertEqual(content, '')
242 
243         # Check that the key has actually been deleted.
244         self.assertFalse(key in self.bucket)
245
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/regression/storage.py b/regression/storage.py
--- a/regression/storage.py
+++ b/regression/storage.py
@@ -82,6 +82,9 @@
         'big': {
             'path': 'regression/data/five-mb-file.zip',
         },
+        'simple': {
+            'path': 'regression/data/simple.txt',
+        }
     }
 
     @staticmethod
@@ -203,6 +206,82 @@
         self.assertEqual(len(last_keys), truncation_size)
 
 
+class TestStoragePseudoHierarchy(TestStorageFiles):
+
+    FILENAMES = [
+        'file01.txt',
+        'parent/file11.txt',
+        'parent/child/file21.txt',
+        'parent/child/file22.txt',
+        'parent/child/grand/file31.txt',
+        'parent/child/other/file32.txt',
+        ]
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestStoragePseudoHierarchy, cls).setUpClass()
+        # Make sure bucket empty before beginning.
+        for key in cls.bucket:
+            key.delete()
+
+        simple_path = cls.FILES['simple']['path']
+        key = cls.bucket.upload_file(simple_path, key=cls.FILENAMES[0])
+        cls.suite_keys_to_delete = [key]
+        for filename in cls.FILENAMES[1:]:
+            new_key = cls.bucket.copy_key(key, cls.bucket, filename)
+            cls.suite_keys_to_delete.append(new_key)
+
+    @classmethod
+    def tearDownClass(cls):
+        for key in cls.suite_keys_to_delete:
+            key.delete()
+
+    def test_root_level_w_delimiter(self):
+        iterator = self.bucket.iterator(delimiter='/')
+        response = iterator.get_next_page_response()
+        keys = list(iterator.get_items_from_response(response))
+        self.assertEqual([key.name for key in keys], ['file01.txt'])
+        self.assertEqual(iterator.page_number, 1)
+        self.assertTrue(iterator.next_page_token is None)
+        self.assertEqual(iterator.prefixes, ('parent/',))
+
+    def test_first_level(self):
+        iterator = self.bucket.iterator(delimiter='/', prefix='parent/')
+        response = iterator.get_next_page_response()
+        keys = list(iterator.get_items_from_response(response))
+        self.assertEqual([key.name for key in keys], ['parent/file11.txt'])
+        self.assertEqual(iterator.page_number, 1)
+        self.assertTrue(iterator.next_page_token is None)
+        self.assertEqual(iterator.prefixes, ('parent/child/',))
+
+    def test_second_level(self):
+        iterator = self.bucket.iterator(delimiter='/', prefix='parent/child/')
+        response = iterator.get_next_page_response()
+        keys = list(iterator.get_items_from_response(response))
+        self.assertEqual([key.name for key in keys],
+                         ['parent/child/file21.txt',
+                          'parent/child/file22.txt'])
+        self.assertEqual(iterator.page_number, 1)
+        self.assertTrue(iterator.next_page_token is None)
+        self.assertEqual(iterator.prefixes,
+                         ('parent/child/grand/', 'parent/child/other/'))
+
+    def test_third_level(self):
+        # Pseudo-hierarchy can be arbitrarily deep, subject to the limit
+        # of 1024 characters in the UTF-8 encoded name:
+        # https://cloud.google.com/storage/docs/bucketnaming#objectnames
+        # Exercise a layer deeper to illustrate this.
+        iterator = self.bucket.iterator(delimiter='/',
+                                        prefix='parent/child/grand/')
+        response = iterator.get_next_page_response()
+        keys = list(iterator.get_items_from_response(response))
+        self.assertEqual([key.name for key in keys],
+                         ['parent/child/grand/file31.txt'])
+        self.assertEqual(iterator.page_number, 1)
+        self.assertTrue(iterator.next_page_token is None)
+        self.assertEqual(iterator.prefixes, ())
+
+
 class TestStorageSignURLs(TestStorageFiles):
 
     def setUp(self):

{"golden_diff": "diff --git a/regression/storage.py b/regression/storage.py\n--- a/regression/storage.py\n+++ b/regression/storage.py\n@@ -82,6 +82,9 @@\n         'big': {\n             'path': 'regression/data/five-mb-file.zip',\n         },\n+        'simple': {\n+            'path': 'regression/data/simple.txt',\n+        }\n     }\n \n     @staticmethod\n@@ -203,6 +206,82 @@\n         self.assertEqual(len(last_keys), truncation_size)\n \n \n+class TestStoragePseudoHierarchy(TestStorageFiles):\n+\n+    FILENAMES = [\n+        'file01.txt',\n+        'parent/file11.txt',\n+        'parent/child/file21.txt',\n+        'parent/child/file22.txt',\n+        'parent/child/grand/file31.txt',\n+        'parent/child/other/file32.txt',\n+        ]\n+\n+    @classmethod\n+    def setUpClass(cls):\n+        super(TestStoragePseudoHierarchy, cls).setUpClass()\n+        # Make sure bucket empty before beginning.\n+        for key in cls.bucket:\n+            key.delete()\n+\n+        simple_path = cls.FILES['simple']['path']\n+        key = cls.bucket.upload_file(simple_path, key=cls.FILENAMES[0])\n+        cls.suite_keys_to_delete = [key]\n+        for filename in cls.FILENAMES[1:]:\n+            new_key = cls.bucket.copy_key(key, cls.bucket, filename)\n+            cls.suite_keys_to_delete.append(new_key)\n+\n+    @classmethod\n+    def tearDownClass(cls):\n+        for key in cls.suite_keys_to_delete:\n+            key.delete()\n+\n+    def test_root_level_w_delimiter(self):\n+        iterator = self.bucket.iterator(delimiter='/')\n+        response = iterator.get_next_page_response()\n+        keys = list(iterator.get_items_from_response(response))\n+        self.assertEqual([key.name for key in keys], ['file01.txt'])\n+        self.assertEqual(iterator.page_number, 1)\n+        self.assertTrue(iterator.next_page_token is None)\n+        self.assertEqual(iterator.prefixes, ('parent/',))\n+\n+    def test_first_level(self):\n+        iterator = self.bucket.iterator(delimiter='/', prefix='parent/')\n+        response = iterator.get_next_page_response()\n+        keys = list(iterator.get_items_from_response(response))\n+        self.assertEqual([key.name for key in keys], ['parent/file11.txt'])\n+        self.assertEqual(iterator.page_number, 1)\n+        self.assertTrue(iterator.next_page_token is None)\n+        self.assertEqual(iterator.prefixes, ('parent/child/',))\n+\n+    def test_second_level(self):\n+        iterator = self.bucket.iterator(delimiter='/', prefix='parent/child/')\n+        response = iterator.get_next_page_response()\n+        keys = list(iterator.get_items_from_response(response))\n+        self.assertEqual([key.name for key in keys],\n+                         ['parent/child/file21.txt',\n+                          'parent/child/file22.txt'])\n+        self.assertEqual(iterator.page_number, 1)\n+        self.assertTrue(iterator.next_page_token is None)\n+        self.assertEqual(iterator.prefixes,\n+                         ('parent/child/grand/', 'parent/child/other/'))\n+\n+    def test_third_level(self):\n+        # Pseudo-hierarchy can be arbitrarily deep, subject to the limit\n+        # of 1024 characters in the UTF-8 encoded name:\n+        # https://cloud.google.com/storage/docs/bucketnaming#objectnames\n+        # Exercise a layer deeper to illustrate this.\n+        iterator = self.bucket.iterator(delimiter='/',\n+                                        prefix='parent/child/grand/')\n+        response = iterator.get_next_page_response()\n+        keys = list(iterator.get_items_from_response(response))\n+        self.assertEqual([key.name for key in keys],\n+                         ['parent/child/grand/file31.txt'])\n+        self.assertEqual(iterator.page_number, 1)\n+        self.assertTrue(iterator.next_page_token is None)\n+        self.assertEqual(iterator.prefixes, ())\n+\n+\n class TestStorageSignURLs(TestStorageFiles):\n \n     def setUp(self):\n", "issue": "Add regression test for datastore keys (object names) with / separator\nSee https://github.com/GoogleCloudPlatform/gcloud-python/pull/371#issuecomment-62659321\n\n", "before_files": [{"content": "from Crypto.Hash import MD5\nimport base64\nimport httplib2\nimport tempfile\nimport time\nimport unittest2\n\nfrom gcloud import storage\n# This assumes the command is being run via tox hence the\n# repository root is the current directory.\nfrom regression import regression_utils\n\n\nHTTP = httplib2.Http()\nSHARED_BUCKETS = {}\n\n\ndef setUpModule():\n    if 'test_bucket' not in SHARED_BUCKETS:\n        connection = regression_utils.get_storage_connection()\n        # %d rounds milliseconds to nearest integer.\n        bucket_name = 'new%d' % (1000 * time.time(),)\n        # In the **very** rare case the bucket name is reserved, this\n        # fails with a ConnectionError.\n        SHARED_BUCKETS['test_bucket'] = connection.create_bucket(bucket_name)\n\n\ndef tearDownModule():\n    for bucket in SHARED_BUCKETS.values():\n        # Passing force=True also deletes all files.\n        bucket.delete(force=True)\n\n\nclass TestStorage(unittest2.TestCase):\n\n    @classmethod\n    def setUpClass(cls):\n        cls.connection = regression_utils.get_storage_connection()\n\n\nclass TestStorageBuckets(TestStorage):\n\n    def setUp(self):\n        self.case_buckets_to_delete = []\n\n    def tearDown(self):\n        for bucket in self.case_buckets_to_delete:\n            bucket.delete()\n\n    def test_create_bucket(self):\n        new_bucket_name = 'a-new-bucket'\n        self.assertRaises(storage.exceptions.NotFound,\n                          self.connection.get_bucket, new_bucket_name)\n        created = self.connection.create_bucket(new_bucket_name)\n        self.case_buckets_to_delete.append(created)\n        self.assertEqual(created.name, new_bucket_name)\n\n    def test_get_buckets(self):\n        buckets_to_create = [\n            'new%d' % (1000 * time.time(),),\n            'newer%d' % (1000 * time.time(),),\n            'newest%d' % (1000 * time.time(),),\n        ]\n        created_buckets = []\n        for bucket_name in buckets_to_create:\n            bucket = self.connection.create_bucket(bucket_name)\n            self.case_buckets_to_delete.append(bucket)\n\n        # Retrieve the buckets.\n        all_buckets = self.connection.get_all_buckets()\n        created_buckets = [bucket for bucket in all_buckets\n                           if bucket.name in buckets_to_create]\n        self.assertEqual(len(created_buckets), len(buckets_to_create))\n\n\nclass TestStorageFiles(TestStorage):\n\n    FILES = {\n        'logo': {\n            'path': 'regression/data/CloudPlatform_128px_Retina.png',\n        },\n        'big': {\n            'path': 'regression/data/five-mb-file.zip',\n        },\n    }\n\n    @staticmethod\n    def _get_base64_md5hash(filename):\n        with open(filename, 'rb') as file_obj:\n            hash = MD5.new(data=file_obj.read())\n        digest_bytes = hash.digest()\n        return base64.b64encode(digest_bytes)\n\n    @classmethod\n    def setUpClass(cls):\n        super(TestStorageFiles, cls).setUpClass()\n        for file_data in cls.FILES.values():\n            file_data['hash'] = cls._get_base64_md5hash(file_data['path'])\n        cls.bucket = SHARED_BUCKETS['test_bucket']\n\n    def setUp(self):\n        self.case_keys_to_delete = []\n\n    def tearDown(self):\n        for key in self.case_keys_to_delete:\n            key.delete()\n\n\nclass TestStorageWriteFiles(TestStorageFiles):\n\n    def test_large_file_write_from_stream(self):\n        key = self.bucket.new_key('LargeFile')\n        self.assertEqual(key._properties, {})\n\n        file_data = self.FILES['big']\n        with open(file_data['path'], 'rb') as file_obj:\n            self.bucket.upload_file_object(file_obj, key=key)\n            self.case_keys_to_delete.append(key)\n\n        key._properties.clear()  # force a reload\n        self.assertEqual(key.md5_hash, file_data['hash'])\n\n    def test_write_metadata(self):\n        key = self.bucket.upload_file(self.FILES['logo']['path'])\n        self.case_keys_to_delete.append(key)\n\n        # NOTE: This should not be necessary. We should be able to pass\n        #       it in to upload_file and also to upload_from_string.\n        key.content_type = 'image/png'\n        key._properties.clear()  # force a reload\n        self.assertEqual(key.content_type, 'image/png')\n\n    def test_direct_write_and_read_into_file(self):\n        key = self.bucket.new_key('MyBuffer')\n        file_contents = 'Hello World'\n        key.upload_from_string(file_contents)\n        self.case_keys_to_delete.append(key)\n\n        same_key = self.bucket.new_key('MyBuffer')\n        temp_filename = tempfile.mktemp()\n        with open(temp_filename, 'w') as file_obj:\n            same_key.get_contents_to_file(file_obj)\n\n        with open(temp_filename, 'rb') as file_obj:\n            stored_contents = file_obj.read()\n\n        self.assertEqual(file_contents, stored_contents)\n\n    def test_copy_existing_file(self):\n        key = self.bucket.upload_file(self.FILES['logo']['path'],\n                                      key='CloudLogo')\n        self.case_keys_to_delete.append(key)\n\n        new_key = self.bucket.copy_key(key, self.bucket, 'CloudLogoCopy')\n        self.case_keys_to_delete.append(new_key)\n\n        base_contents = key.get_contents_as_string()\n        copied_contents = new_key.get_contents_as_string()\n        self.assertEqual(base_contents, copied_contents)\n\n\nclass TestStorageListFiles(TestStorageFiles):\n\n    FILENAMES = ['CloudLogo1', 'CloudLogo2', 'CloudLogo3']\n\n    @classmethod\n    def setUpClass(cls):\n        super(TestStorageListFiles, cls).setUpClass()\n        # Make sure bucket empty before beginning.\n        for key in cls.bucket:\n            key.delete()\n\n        logo_path = cls.FILES['logo']['path']\n        key = cls.bucket.upload_file(logo_path, key=cls.FILENAMES[0])\n        cls.suite_keys_to_delete = [key]\n\n        # Copy main key onto remaining in FILENAMES.\n        for filename in cls.FILENAMES[1:]:\n            new_key = cls.bucket.copy_key(key, cls.bucket, filename)\n            cls.suite_keys_to_delete.append(new_key)\n\n    @classmethod\n    def tearDownClass(cls):\n        for key in cls.suite_keys_to_delete:\n            key.delete()\n\n    def test_list_files(self):\n        all_keys = self.bucket.get_all_keys()\n        self.assertEqual(len(all_keys), len(self.FILENAMES))\n\n    def test_paginate_files(self):\n        truncation_size = 1\n        count = len(self.FILENAMES) - truncation_size\n        iterator = self.bucket.iterator(max_results=count)\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual(len(keys), count)\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is not None)\n\n        response = iterator.get_next_page_response()\n        last_keys = list(iterator.get_items_from_response(response))\n        self.assertEqual(len(last_keys), truncation_size)\n\n\nclass TestStorageSignURLs(TestStorageFiles):\n\n    def setUp(self):\n        super(TestStorageSignURLs, self).setUp()\n\n        logo_path = self.FILES['logo']['path']\n        with open(logo_path, 'r') as file_obj:\n            self.LOCAL_FILE = file_obj.read()\n\n        key = self.bucket.new_key('LogoToSign.jpg')\n        key.upload_from_string(self.LOCAL_FILE)\n        self.case_keys_to_delete.append(key)\n\n    def tearDown(self):\n        for key in self.case_keys_to_delete:\n            if key.exists():\n                key.delete()\n\n    def test_create_signed_read_url(self):\n        key = self.bucket.new_key('LogoToSign.jpg')\n        expiration = int(time.time() + 5)\n        signed_url = key.generate_signed_url(expiration, method='GET')\n\n        response, content = HTTP.request(signed_url, method='GET')\n        self.assertEqual(response.status, 200)\n        self.assertEqual(content, self.LOCAL_FILE)\n\n    def test_create_signed_delete_url(self):\n        key = self.bucket.new_key('LogoToSign.jpg')\n        expiration = int(time.time() + 283473274)\n        signed_delete_url = key.generate_signed_url(expiration,\n                                                    method='DELETE')\n\n        response, content = HTTP.request(signed_delete_url, method='DELETE')\n        self.assertEqual(response.status, 204)\n        self.assertEqual(content, '')\n\n        # Check that the key has actually been deleted.\n        self.assertFalse(key in self.bucket)\n", "path": "regression/storage.py"}], "after_files": [{"content": "from Crypto.Hash import MD5\nimport base64\nimport httplib2\nimport tempfile\nimport time\nimport unittest2\n\nfrom gcloud import storage\n# This assumes the command is being run via tox hence the\n# repository root is the current directory.\nfrom regression import regression_utils\n\n\nHTTP = httplib2.Http()\nSHARED_BUCKETS = {}\n\n\ndef setUpModule():\n    if 'test_bucket' not in SHARED_BUCKETS:\n        connection = regression_utils.get_storage_connection()\n        # %d rounds milliseconds to nearest integer.\n        bucket_name = 'new%d' % (1000 * time.time(),)\n        # In the **very** rare case the bucket name is reserved, this\n        # fails with a ConnectionError.\n        SHARED_BUCKETS['test_bucket'] = connection.create_bucket(bucket_name)\n\n\ndef tearDownModule():\n    for bucket in SHARED_BUCKETS.values():\n        # Passing force=True also deletes all files.\n        bucket.delete(force=True)\n\n\nclass TestStorage(unittest2.TestCase):\n\n    @classmethod\n    def setUpClass(cls):\n        cls.connection = regression_utils.get_storage_connection()\n\n\nclass TestStorageBuckets(TestStorage):\n\n    def setUp(self):\n        self.case_buckets_to_delete = []\n\n    def tearDown(self):\n        for bucket in self.case_buckets_to_delete:\n            bucket.delete()\n\n    def test_create_bucket(self):\n        new_bucket_name = 'a-new-bucket'\n        self.assertRaises(storage.exceptions.NotFound,\n                          self.connection.get_bucket, new_bucket_name)\n        created = self.connection.create_bucket(new_bucket_name)\n        self.case_buckets_to_delete.append(created)\n        self.assertEqual(created.name, new_bucket_name)\n\n    def test_get_buckets(self):\n        buckets_to_create = [\n            'new%d' % (1000 * time.time(),),\n            'newer%d' % (1000 * time.time(),),\n            'newest%d' % (1000 * time.time(),),\n        ]\n        created_buckets = []\n        for bucket_name in buckets_to_create:\n            bucket = self.connection.create_bucket(bucket_name)\n            self.case_buckets_to_delete.append(bucket)\n\n        # Retrieve the buckets.\n        all_buckets = self.connection.get_all_buckets()\n        created_buckets = [bucket for bucket in all_buckets\n                           if bucket.name in buckets_to_create]\n        self.assertEqual(len(created_buckets), len(buckets_to_create))\n\n\nclass TestStorageFiles(TestStorage):\n\n    FILES = {\n        'logo': {\n            'path': 'regression/data/CloudPlatform_128px_Retina.png',\n        },\n        'big': {\n            'path': 'regression/data/five-mb-file.zip',\n        },\n        'simple': {\n            'path': 'regression/data/simple.txt',\n        }\n    }\n\n    @staticmethod\n    def _get_base64_md5hash(filename):\n        with open(filename, 'rb') as file_obj:\n            hash = MD5.new(data=file_obj.read())\n        digest_bytes = hash.digest()\n        return base64.b64encode(digest_bytes)\n\n    @classmethod\n    def setUpClass(cls):\n        super(TestStorageFiles, cls).setUpClass()\n        for file_data in cls.FILES.values():\n            file_data['hash'] = cls._get_base64_md5hash(file_data['path'])\n        cls.bucket = SHARED_BUCKETS['test_bucket']\n\n    def setUp(self):\n        self.case_keys_to_delete = []\n\n    def tearDown(self):\n        for key in self.case_keys_to_delete:\n            key.delete()\n\n\nclass TestStorageWriteFiles(TestStorageFiles):\n\n    def test_large_file_write_from_stream(self):\n        key = self.bucket.new_key('LargeFile')\n        self.assertEqual(key._properties, {})\n\n        file_data = self.FILES['big']\n        with open(file_data['path'], 'rb') as file_obj:\n            self.bucket.upload_file_object(file_obj, key=key)\n            self.case_keys_to_delete.append(key)\n\n        key._properties.clear()  # force a reload\n        self.assertEqual(key.md5_hash, file_data['hash'])\n\n    def test_write_metadata(self):\n        key = self.bucket.upload_file(self.FILES['logo']['path'])\n        self.case_keys_to_delete.append(key)\n\n        # NOTE: This should not be necessary. We should be able to pass\n        #       it in to upload_file and also to upload_from_string.\n        key.content_type = 'image/png'\n        key._properties.clear()  # force a reload\n        self.assertEqual(key.content_type, 'image/png')\n\n    def test_direct_write_and_read_into_file(self):\n        key = self.bucket.new_key('MyBuffer')\n        file_contents = 'Hello World'\n        key.upload_from_string(file_contents)\n        self.case_keys_to_delete.append(key)\n\n        same_key = self.bucket.new_key('MyBuffer')\n        temp_filename = tempfile.mktemp()\n        with open(temp_filename, 'w') as file_obj:\n            same_key.get_contents_to_file(file_obj)\n\n        with open(temp_filename, 'rb') as file_obj:\n            stored_contents = file_obj.read()\n\n        self.assertEqual(file_contents, stored_contents)\n\n    def test_copy_existing_file(self):\n        key = self.bucket.upload_file(self.FILES['logo']['path'],\n                                      key='CloudLogo')\n        self.case_keys_to_delete.append(key)\n\n        new_key = self.bucket.copy_key(key, self.bucket, 'CloudLogoCopy')\n        self.case_keys_to_delete.append(new_key)\n\n        base_contents = key.get_contents_as_string()\n        copied_contents = new_key.get_contents_as_string()\n        self.assertEqual(base_contents, copied_contents)\n\n\nclass TestStorageListFiles(TestStorageFiles):\n\n    FILENAMES = ['CloudLogo1', 'CloudLogo2', 'CloudLogo3']\n\n    @classmethod\n    def setUpClass(cls):\n        super(TestStorageListFiles, cls).setUpClass()\n        # Make sure bucket empty before beginning.\n        for key in cls.bucket:\n            key.delete()\n\n        logo_path = cls.FILES['logo']['path']\n        key = cls.bucket.upload_file(logo_path, key=cls.FILENAMES[0])\n        cls.suite_keys_to_delete = [key]\n\n        # Copy main key onto remaining in FILENAMES.\n        for filename in cls.FILENAMES[1:]:\n            new_key = cls.bucket.copy_key(key, cls.bucket, filename)\n            cls.suite_keys_to_delete.append(new_key)\n\n    @classmethod\n    def tearDownClass(cls):\n        for key in cls.suite_keys_to_delete:\n            key.delete()\n\n    def test_list_files(self):\n        all_keys = self.bucket.get_all_keys()\n        self.assertEqual(len(all_keys), len(self.FILENAMES))\n\n    def test_paginate_files(self):\n        truncation_size = 1\n        count = len(self.FILENAMES) - truncation_size\n        iterator = self.bucket.iterator(max_results=count)\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual(len(keys), count)\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is not None)\n\n        response = iterator.get_next_page_response()\n        last_keys = list(iterator.get_items_from_response(response))\n        self.assertEqual(len(last_keys), truncation_size)\n\n\nclass TestStoragePseudoHierarchy(TestStorageFiles):\n\n    FILENAMES = [\n        'file01.txt',\n        'parent/file11.txt',\n        'parent/child/file21.txt',\n        'parent/child/file22.txt',\n        'parent/child/grand/file31.txt',\n        'parent/child/other/file32.txt',\n        ]\n\n    @classmethod\n    def setUpClass(cls):\n        super(TestStoragePseudoHierarchy, cls).setUpClass()\n        # Make sure bucket empty before beginning.\n        for key in cls.bucket:\n            key.delete()\n\n        simple_path = cls.FILES['simple']['path']\n        key = cls.bucket.upload_file(simple_path, key=cls.FILENAMES[0])\n        cls.suite_keys_to_delete = [key]\n        for filename in cls.FILENAMES[1:]:\n            new_key = cls.bucket.copy_key(key, cls.bucket, filename)\n            cls.suite_keys_to_delete.append(new_key)\n\n    @classmethod\n    def tearDownClass(cls):\n        for key in cls.suite_keys_to_delete:\n            key.delete()\n\n    def test_root_level_w_delimiter(self):\n        iterator = self.bucket.iterator(delimiter='/')\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual([key.name for key in keys], ['file01.txt'])\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is None)\n        self.assertEqual(iterator.prefixes, ('parent/',))\n\n    def test_first_level(self):\n        iterator = self.bucket.iterator(delimiter='/', prefix='parent/')\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual([key.name for key in keys], ['parent/file11.txt'])\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is None)\n        self.assertEqual(iterator.prefixes, ('parent/child/',))\n\n    def test_second_level(self):\n        iterator = self.bucket.iterator(delimiter='/', prefix='parent/child/')\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual([key.name for key in keys],\n                         ['parent/child/file21.txt',\n                          'parent/child/file22.txt'])\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is None)\n        self.assertEqual(iterator.prefixes,\n                         ('parent/child/grand/', 'parent/child/other/'))\n\n    def test_third_level(self):\n        # Pseudo-hierarchy can be arbitrarily deep, subject to the limit\n        # of 1024 characters in the UTF-8 encoded name:\n        # https://cloud.google.com/storage/docs/bucketnaming#objectnames\n        # Exercise a layer deeper to illustrate this.\n        iterator = self.bucket.iterator(delimiter='/',\n                                        prefix='parent/child/grand/')\n        response = iterator.get_next_page_response()\n        keys = list(iterator.get_items_from_response(response))\n        self.assertEqual([key.name for key in keys],\n                         ['parent/child/grand/file31.txt'])\n        self.assertEqual(iterator.page_number, 1)\n        self.assertTrue(iterator.next_page_token is None)\n        self.assertEqual(iterator.prefixes, ())\n\n\nclass TestStorageSignURLs(TestStorageFiles):\n\n    def setUp(self):\n        super(TestStorageSignURLs, self).setUp()\n\n        logo_path = self.FILES['logo']['path']\n        with open(logo_path, 'r') as file_obj:\n            self.LOCAL_FILE = file_obj.read()\n\n        key = self.bucket.new_key('LogoToSign.jpg')\n        key.upload_from_string(self.LOCAL_FILE)\n        self.case_keys_to_delete.append(key)\n\n    def tearDown(self):\n        for key in self.case_keys_to_delete:\n            if key.exists():\n                key.delete()\n\n    def test_create_signed_read_url(self):\n        key = self.bucket.new_key('LogoToSign.jpg')\n        expiration = int(time.time() + 5)\n        signed_url = key.generate_signed_url(expiration, method='GET')\n\n        response, content = HTTP.request(signed_url, method='GET')\n        self.assertEqual(response.status, 200)\n        self.assertEqual(content, self.LOCAL_FILE)\n\n    def test_create_signed_delete_url(self):\n        key = self.bucket.new_key('LogoToSign.jpg')\n        expiration = int(time.time() + 283473274)\n        signed_delete_url = key.generate_signed_url(expiration,\n                                                    method='DELETE')\n\n        response, content = HTTP.request(signed_delete_url, method='DELETE')\n        self.assertEqual(response.status, 204)\n        self.assertEqual(content, '')\n\n        # Check that the key has actually been deleted.\n        self.assertFalse(key in self.bucket)\n", "path": "regression/storage.py"}]}