| OLD | NEW |
| (Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # Copyright (c) 2006-2011 Mitch Garnaat http://garnaat.org/ |
| 3 # Copyright (c) 2010, Eucalyptus Systems, Inc. |
| 4 # Copyright (c) 2011, Nexenta Systems, Inc. |
| 5 # All rights reserved. |
| 6 # |
| 7 # Permission is hereby granted, free of charge, to any person obtaining a |
| 8 # copy of this software and associated documentation files (the |
| 9 # "Software"), to deal in the Software without restriction, including |
| 10 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 11 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 12 # persons to whom the Software is furnished to do so, subject to the fol- |
| 13 # lowing conditions: |
| 14 # |
| 15 # The above copyright notice and this permission notice shall be included |
| 16 # in all copies or substantial portions of the Software. |
| 17 # |
| 18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 19 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 20 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 21 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 22 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 24 # IN THE SOFTWARE. |
| 25 |
| 26 """ |
| 27 Some unit tests for the GSConnection |
| 28 """ |
| 29 |
| 30 import unittest |
| 31 import time |
| 32 import os |
| 33 import re |
| 34 import xml |
| 35 from boto.gs.connection import GSConnection |
| 36 from boto.gs.cors import Cors |
| 37 from boto import handler |
| 38 from boto import storage_uri |
| 39 |
| 40 class GSConnectionTest (unittest.TestCase): |
| 41 |
| 42 def test_1_basic(self): |
| 43 """basic regression test for Google Cloud Storage""" |
| 44 print '--- running GSConnection tests ---' |
| 45 c = GSConnection() |
| 46 # create a new, empty bucket |
| 47 bucket_name = 'test-%d' % int(time.time()) |
| 48 bucket = c.create_bucket(bucket_name) |
| 49 # now try a get_bucket call and see if it's really there |
| 50 bucket = c.get_bucket(bucket_name) |
| 51 k = bucket.new_key() |
| 52 k.name = 'foobar' |
| 53 s1 = 'This is a test of file upload and download' |
| 54 s2 = 'This is a second string to test file upload and download' |
| 55 k.set_contents_from_string(s1) |
| 56 fp = open('foobar', 'wb') |
| 57 # now get the contents from s3 to a local file |
| 58 k.get_contents_to_file(fp) |
| 59 fp.close() |
| 60 fp = open('foobar') |
| 61 # check to make sure content read from s3 is identical to original |
| 62 assert s1 == fp.read(), 'corrupted file' |
| 63 fp.close() |
| 64 bucket.delete_key(k) |
| 65 # test a few variations on get_all_keys - first load some data |
| 66 # for the first one, let's override the content type |
| 67 phony_mimetype = 'application/x-boto-test' |
| 68 headers = {'Content-Type': phony_mimetype} |
| 69 k.name = 'foo/bar' |
| 70 k.set_contents_from_string(s1, headers) |
| 71 k.name = 'foo/bas' |
| 72 k.set_contents_from_filename('foobar') |
| 73 k.name = 'foo/bat' |
| 74 k.set_contents_from_string(s1) |
| 75 k.name = 'fie/bar' |
| 76 k.set_contents_from_string(s1) |
| 77 k.name = 'fie/bas' |
| 78 k.set_contents_from_string(s1) |
| 79 k.name = 'fie/bat' |
| 80 k.set_contents_from_string(s1) |
| 81 # try resetting the contents to another value |
| 82 md5 = k.md5 |
| 83 k.set_contents_from_string(s2) |
| 84 assert k.md5 != md5 |
| 85 # Test for stream API |
| 86 fp2 = open('foobar', 'rb') |
| 87 k.md5 = None |
| 88 k.base64md5 = None |
| 89 k.set_contents_from_stream(fp2, headers=headers) |
| 90 fp = open('foobar1', 'wb') |
| 91 k.get_contents_to_file(fp) |
| 92 fp.close() |
| 93 fp2.seek(0,0) |
| 94 fp = open('foobar1', 'rb') |
| 95 assert (fp2.read() == fp.read()), 'Chunked Transfer corrupted the Data' |
| 96 fp.close() |
| 97 fp2.close() |
| 98 os.unlink('foobar1') |
| 99 os.unlink('foobar') |
| 100 all = bucket.get_all_keys() |
| 101 assert len(all) == 6 |
| 102 rs = bucket.get_all_keys(prefix='foo') |
| 103 assert len(rs) == 3 |
| 104 rs = bucket.get_all_keys(prefix='', delimiter='/') |
| 105 assert len(rs) == 2 |
| 106 rs = bucket.get_all_keys(maxkeys=5) |
| 107 assert len(rs) == 5 |
| 108 # test the lookup method |
| 109 k = bucket.lookup('foo/bar') |
| 110 assert isinstance(k, bucket.key_class) |
| 111 assert k.content_type == phony_mimetype |
| 112 k = bucket.lookup('notthere') |
| 113 assert k == None |
| 114 # try some metadata stuff |
| 115 k = bucket.new_key() |
| 116 k.name = 'has_metadata' |
| 117 mdkey1 = 'meta1' |
| 118 mdval1 = 'This is the first metadata value' |
| 119 k.set_metadata(mdkey1, mdval1) |
| 120 mdkey2 = 'meta2' |
| 121 mdval2 = 'This is the second metadata value' |
| 122 k.set_metadata(mdkey2, mdval2) |
| 123 # try a unicode metadata value |
| 124 |
| 125 mdval3 = u'föö' |
| 126 mdkey3 = 'meta3' |
| 127 k.set_metadata(mdkey3, mdval3) |
| 128 k.set_contents_from_string(s1) |
| 129 |
| 130 k = bucket.lookup('has_metadata') |
| 131 assert k.get_metadata(mdkey1) == mdval1 |
| 132 assert k.get_metadata(mdkey2) == mdval2 |
| 133 assert k.get_metadata(mdkey3) == mdval3 |
| 134 k = bucket.new_key() |
| 135 k.name = 'has_metadata' |
| 136 k.get_contents_as_string() |
| 137 assert k.get_metadata(mdkey1) == mdval1 |
| 138 assert k.get_metadata(mdkey2) == mdval2 |
| 139 assert k.get_metadata(mdkey3) == mdval3 |
| 140 bucket.delete_key(k) |
| 141 # test list and iterator |
| 142 rs1 = bucket.list() |
| 143 num_iter = 0 |
| 144 for r in rs1: |
| 145 num_iter = num_iter + 1 |
| 146 rs = bucket.get_all_keys() |
| 147 num_keys = len(rs) |
| 148 assert num_iter == num_keys |
| 149 # try some acl stuff |
| 150 bucket.set_acl('public-read') |
| 151 acl = bucket.get_acl() |
| 152 assert len(acl.entries.entry_list) == 2 |
| 153 bucket.set_acl('private') |
| 154 acl = bucket.get_acl() |
| 155 assert len(acl.entries.entry_list) == 1 |
| 156 k = bucket.lookup('foo/bar') |
| 157 k.set_acl('public-read') |
| 158 acl = k.get_acl() |
| 159 assert len(acl.entries.entry_list) == 2 |
| 160 k.set_acl('private') |
| 161 acl = k.get_acl() |
| 162 assert len(acl.entries.entry_list) == 1 |
| 163 # try set/get raw logging subresource |
| 164 empty_logging_str="<?xml version='1.0' encoding='UTF-8'?><Logging/>" |
| 165 logging_str = ( |
| 166 "<?xml version='1.0' encoding='UTF-8'?><Logging>" |
| 167 "<LogBucket>log-bucket</LogBucket>" + |
| 168 "<LogObjectPrefix>example</LogObjectPrefix>" + |
| 169 "</Logging>") |
| 170 bucket.set_subresource('logging', logging_str); |
| 171 assert bucket.get_subresource('logging') == logging_str; |
| 172 # try disable/enable logging |
| 173 bucket.disable_logging() |
| 174 assert bucket.get_subresource('logging') == empty_logging_str |
| 175 bucket.enable_logging('log-bucket', 'example') |
| 176 assert bucket.get_subresource('logging') == logging_str; |
| 177 # now delete all keys in bucket |
| 178 for k in bucket: |
| 179 bucket.delete_key(k) |
| 180 # now delete bucket |
| 181 time.sleep(5) |
| 182 c.delete_bucket(bucket) |
| 183 |
| 184 def test_2_copy_key(self): |
| 185 """test copying a key from one bucket to another""" |
| 186 c = GSConnection() |
| 187 # create two new, empty buckets |
| 188 bucket_name_1 = 'test1-%d' % int(time.time()) |
| 189 bucket_name_2 = 'test2-%d' % int(time.time()) |
| 190 bucket1 = c.create_bucket(bucket_name_1) |
| 191 bucket2 = c.create_bucket(bucket_name_2) |
| 192 # verify buckets got created |
| 193 bucket1 = c.get_bucket(bucket_name_1) |
| 194 bucket2 = c.get_bucket(bucket_name_2) |
| 195 # create a key in bucket1 and give it some content |
| 196 k1 = bucket1.new_key() |
| 197 assert isinstance(k1, bucket1.key_class) |
| 198 key_name = 'foobar' |
| 199 k1.name = key_name |
| 200 s = 'This is a test.' |
| 201 k1.set_contents_from_string(s) |
| 202 # copy the new key from bucket1 to bucket2 |
| 203 k1.copy(bucket_name_2, key_name) |
| 204 # now copy the contents from bucket2 to a local file |
| 205 k2 = bucket2.lookup(key_name) |
| 206 assert isinstance(k2, bucket2.key_class) |
| 207 fp = open('foobar', 'wb') |
| 208 k2.get_contents_to_file(fp) |
| 209 fp.close() |
| 210 fp = open('foobar') |
| 211 # check to make sure content read is identical to original |
| 212 assert s == fp.read(), 'move test failed!' |
| 213 fp.close() |
| 214 # delete keys |
| 215 bucket1.delete_key(k1) |
| 216 bucket2.delete_key(k2) |
| 217 # delete test buckets |
| 218 c.delete_bucket(bucket1) |
| 219 c.delete_bucket(bucket2) |
| 220 |
| 221 def test_3_default_object_acls(self): |
| 222 """test default object acls""" |
| 223 # regexp for matching project-private default object ACL |
| 224 project_private_re = '\s*<AccessControlList>\s*<Entries>\s*<Entry>' \ |
| 225 '\s*<Scope type="GroupById"><ID>[0-9a-fA-F]+</ID></Scope>' \ |
| 226 '\s*<Permission>FULL_CONTROL</Permission>\s*</Entry>\s*<Entry>' \ |
| 227 '\s*<Scope type="GroupById"><ID>[0-9a-fA-F]+</ID></Scope>' \ |
| 228 '\s*<Permission>FULL_CONTROL</Permission>\s*</Entry>\s*<Entry>' \ |
| 229 '\s*<Scope type="GroupById"><ID>[0-9a-fA-F]+</ID></Scope>' \ |
| 230 '\s*<Permission>READ</Permission></Entry>\s*</Entries>' \ |
| 231 '\s*</AccessControlList>\s*' |
| 232 c = GSConnection() |
| 233 # create a new bucket |
| 234 bucket_name = 'test-%d' % int(time.time()) |
| 235 bucket = c.create_bucket(bucket_name) |
| 236 # now call get_bucket to see if it's really there |
| 237 bucket = c.get_bucket(bucket_name) |
| 238 # get default acl and make sure it's project-private |
| 239 acl = bucket.get_def_acl() |
| 240 assert re.search(project_private_re, acl.to_xml()) |
| 241 # set default acl to a canned acl and verify it gets set |
| 242 bucket.set_def_acl('public-read') |
| 243 acl = bucket.get_def_acl() |
| 244 # save public-read acl for later test |
| 245 public_read_acl = acl |
| 246 assert acl.to_xml() == ('<AccessControlList><Entries><Entry>' + |
| 247 '<Scope type="AllUsers"></Scope><Permission>READ</Permission>' + |
| 248 '</Entry></Entries></AccessControlList>') |
| 249 # back to private acl |
| 250 bucket.set_def_acl('private') |
| 251 acl = bucket.get_def_acl() |
| 252 assert acl.to_xml() == '<AccessControlList></AccessControlList>' |
| 253 # set default acl to an xml acl and verify it gets set |
| 254 bucket.set_def_acl(public_read_acl) |
| 255 acl = bucket.get_def_acl() |
| 256 assert acl.to_xml() == ('<AccessControlList><Entries><Entry>' + |
| 257 '<Scope type="AllUsers"></Scope><Permission>READ</Permission>' + |
| 258 '</Entry></Entries></AccessControlList>') |
| 259 # back to private acl |
| 260 bucket.set_def_acl('private') |
| 261 acl = bucket.get_def_acl() |
| 262 assert acl.to_xml() == '<AccessControlList></AccessControlList>' |
| 263 # delete bucket |
| 264 c.delete_bucket(bucket) |
| 265 # repeat default acl tests using boto's storage_uri interface |
| 266 # create a new bucket |
| 267 bucket_name = 'test-%d' % int(time.time()) |
| 268 uri = storage_uri('gs://' + bucket_name) |
| 269 uri.create_bucket() |
| 270 # get default acl and make sure it's project-private |
| 271 acl = uri.get_def_acl() |
| 272 assert re.search(project_private_re, acl.to_xml()) |
| 273 # set default acl to a canned acl and verify it gets set |
| 274 uri.set_def_acl('public-read') |
| 275 acl = uri.get_def_acl() |
| 276 # save public-read acl for later test |
| 277 public_read_acl = acl |
| 278 assert acl.to_xml() == ('<AccessControlList><Entries><Entry>' + |
| 279 '<Scope type="AllUsers"></Scope><Permission>READ</Permission>' + |
| 280 '</Entry></Entries></AccessControlList>') |
| 281 # back to private acl |
| 282 uri.set_def_acl('private') |
| 283 acl = uri.get_def_acl() |
| 284 assert acl.to_xml() == '<AccessControlList></AccessControlList>' |
| 285 # set default acl to an xml acl and verify it gets set |
| 286 uri.set_def_acl(public_read_acl) |
| 287 acl = uri.get_def_acl() |
| 288 assert acl.to_xml() == ('<AccessControlList><Entries><Entry>' + |
| 289 '<Scope type="AllUsers"></Scope><Permission>READ</Permission>' + |
| 290 '</Entry></Entries></AccessControlList>') |
| 291 # back to private acl |
| 292 uri.set_def_acl('private') |
| 293 acl = uri.get_def_acl() |
| 294 assert acl.to_xml() == '<AccessControlList></AccessControlList>' |
| 295 # delete bucket |
| 296 uri.delete_bucket() |
| 297 |
| 298 def test_4_cors_xml(self): |
| 299 """test setting and getting of CORS XML documents""" |
| 300 # regexp for matching project-private default object ACL |
| 301 cors_empty = '<CorsConfig></CorsConfig>' |
| 302 cors_doc = ('<CorsConfig><Cors><Origins><Origin>origin1.example.com' |
| 303 '</Origin><Origin>origin2.example.com</Origin></Origins>' |
| 304 '<Methods><Method>GET</Method><Method>PUT</Method>' |
| 305 '<Method>POST</Method></Methods><ResponseHeaders>' |
| 306 '<ResponseHeader>foo</ResponseHeader>' |
| 307 '<ResponseHeader>bar</ResponseHeader></ResponseHeaders>' |
| 308 '</Cors></CorsConfig>') |
| 309 c = GSConnection() |
| 310 # create a new bucket |
| 311 bucket_name = 'test-%d' % int(time.time()) |
| 312 bucket = c.create_bucket(bucket_name) |
| 313 # now call get_bucket to see if it's really there |
| 314 bucket = c.get_bucket(bucket_name) |
| 315 # get new bucket cors and make sure it's empty |
| 316 cors = re.sub(r'\s', '', bucket.get_cors().to_xml()) |
| 317 assert cors == cors_empty |
| 318 # set cors document on new bucket |
| 319 bucket.set_cors(cors_doc) |
| 320 cors = re.sub(r'\s', '', bucket.get_cors().to_xml()) |
| 321 assert cors == cors_doc |
| 322 # delete bucket |
| 323 c.delete_bucket(bucket) |
| 324 |
| 325 # repeat cors tests using boto's storage_uri interface |
| 326 # create a new bucket |
| 327 bucket_name = 'test-%d' % int(time.time()) |
| 328 uri = storage_uri('gs://' + bucket_name) |
| 329 uri.create_bucket() |
| 330 # get new bucket cors and make sure it's empty |
| 331 cors = re.sub(r'\s', '', uri.get_cors().to_xml()) |
| 332 assert cors == cors_empty |
| 333 # set cors document on new bucket |
| 334 cors_obj = Cors() |
| 335 h = handler.XmlHandler(cors_obj, None) |
| 336 xml.sax.parseString(cors_doc, h) |
| 337 uri.set_cors(cors_obj) |
| 338 cors = re.sub(r'\s', '', uri.get_cors().to_xml()) |
| 339 assert cors == cors_doc |
| 340 # delete bucket |
| 341 uri.delete_bucket() |
| 342 |
| 343 print '--- tests completed ---' |
| OLD | NEW |