Revision 33ffca25 pithos/api/tests.py
b/pithos/api/tests.py | ||
---|---|---|
71 | 71 |
'Content-Type', |
72 | 72 |
'Last-Modified', |
73 | 73 |
'Content-Length', |
74 |
'Date',), |
|
74 |
'Date', |
|
75 |
'X-Container-Block-Size', |
|
76 |
'X-Container-Block-Hash',), |
|
75 | 77 |
'object':( |
76 | 78 |
'ETag', |
77 | 79 |
'Content-Length', |
... | ... | |
132 | 134 |
self.assert_headers(response, 'account', exp_meta) |
133 | 135 |
return response |
134 | 136 |
|
135 |
def list_containers(self, account, limit=10000, marker='', format='', **headers): |
|
137 |
def list_containers(self, account, limit=10000, marker='', format='', |
|
138 |
**headers): |
|
136 | 139 |
params = locals() |
137 | 140 |
params.pop('self') |
138 | 141 |
params.pop('account') |
... | ... | |
167 | 170 |
self.assert_headers(response, 'container', exp_meta) |
168 | 171 |
return response |
169 | 172 |
|
170 |
def list_objects(self, account, container, limit=10000, marker='', prefix='', format='', path='', delimiter='', meta='', **headers): |
|
173 |
def list_objects(self, account, container, limit=10000, marker='', |
|
174 |
prefix='', format='', path='', delimiter='', meta='', |
|
175 |
**headers): |
|
171 | 176 |
params = locals() |
172 | 177 |
params.pop('self') |
173 | 178 |
params.pop('account') |
... | ... | |
189 | 194 |
|
190 | 195 |
def update_container_meta(self, account, name, **meta): |
191 | 196 |
path = '/v1/%s/%s' %(account, name) |
192 |
response = self.client.post(path, data={}, content_type='text/xml', follow=False, **meta) |
|
197 |
response = self.client.post(path, |
|
198 |
data=None, |
|
199 |
content_type='text/xml', |
|
200 |
follow=False, **meta) |
|
193 | 201 |
response.content = response.content.strip() |
194 | 202 |
self.assert_status(response, 202) |
195 | 203 |
return response |
... | ... | |
217 | 225 |
self.assert_headers(response, 'object') |
218 | 226 |
return response |
219 | 227 |
|
220 |
def upload_object(self, account, container, name, data, content_type='application/json', **headers): |
|
228 |
def upload_object(self, account, container, name, data, content_type='', |
|
229 |
**headers): |
|
221 | 230 |
path = '/v1/%s/%s/%s' %(account, container, name) |
222 | 231 |
response = self.client.put(path, data, content_type, **headers) |
223 | 232 |
response.content = response.content.strip() |
... | ... | |
242 | 251 |
self.assert_status(response, 201) |
243 | 252 |
return response |
244 | 253 |
|
245 |
def update_object_meta(self, account, container, name, **headers): |
|
254 |
def update_object(self, account, container, name, data={}, |
|
255 |
content_type='MULTIPART_CONTENT', **headers): |
|
246 | 256 |
path = '/v1/%s/%s/%s' %(account, container, name) |
247 |
response = self.client.post(path, **headers) |
|
257 |
response = self.client.post(path, data, content_type, **headers)
|
|
248 | 258 |
response.content = response.content.strip() |
249 |
self.assert_status(response, 202)
|
|
259 |
self.assert_status(response, [202, 204, 416])
|
|
250 | 260 |
return response |
251 | 261 |
|
252 | 262 |
def delete_object(self, account, container, name): |
... | ... | |
260 | 270 |
entities = ['Account', 'Container', 'Container-Object', 'Object'] |
261 | 271 |
user_defined_meta = ['X-%s-Meta' %elem for elem in entities] |
262 | 272 |
headers = [item for item in response._headers.values()] |
263 |
system_headers = [h for h in headers if not h[0].startswith(tuple(user_defined_meta))] |
|
273 |
t = tuple(user_defined_meta) |
|
274 |
system_headers = [h for h in headers if not h[0].startswith(t)] |
|
264 | 275 |
for h in system_headers: |
265 | 276 |
self.assertTrue(h[0] in self.headers[type]) |
266 | 277 |
if exp_meta: |
267 | 278 |
self.assertEqual(h[1], exp_meta[h[0]]) |
268 | 279 |
|
269 | 280 |
def assert_extended(self, response, format, type, size): |
270 |
self.assertEqual(response['Content-Type'].find(self.contentTypes[format]), 0) |
|
281 |
exp_content_type = self.contentTypes[format] |
|
282 |
self.assertEqual(response['Content-Type'].find(exp_content_type), 0) |
|
271 | 283 |
if format == 'xml': |
272 | 284 |
self.assert_xml(response, type, size) |
273 | 285 |
elif format == 'json': |
... | ... | |
307 | 319 |
except IOError: |
308 | 320 |
return |
309 | 321 |
|
310 |
def upload_random_data(self, account, container, name, length=1024, meta={}):
|
|
311 |
char_set = string.ascii_uppercase + string.digits
|
|
312 |
data = ''.join(random.choice(char_set) for x in range(length))
|
|
322 |
def upload_random_data(self, account, container, name, length=1024, |
|
323 |
meta={}):
|
|
324 |
data = get_random_data(length)
|
|
313 | 325 |
return self.upload_data(account, container, name, data, meta) |
314 | 326 |
|
315 | 327 |
def upload_data(self, account, container, name, data, meta={}): |
... | ... | |
320 | 332 |
obj['hash'] = compute_md5_hash(obj['data']) |
321 | 333 |
meta.update({'HTTP_X_OBJECT_META_TEST':'test1', |
322 | 334 |
'HTTP_ETAG':obj['hash']}) |
323 |
meta['HTTP_CONTENT_TYPE'], enc = mimetypes.guess_type(name) |
|
335 |
type, enc = mimetypes.guess_type(name) |
|
336 |
meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text' |
|
324 | 337 |
if enc: |
325 |
meta['HTTP_CONTENT_TYPE'] = enc |
|
338 |
meta['HTTP_CONTENT_ENCODING'] = enc |
|
339 |
|
|
326 | 340 |
obj['meta'] = meta |
327 | 341 |
r = self.upload_object(account, |
328 | 342 |
container, |
... | ... | |
351 | 365 |
response = self.get_account_meta(self.account) |
352 | 366 |
r2 = self.list_containers(self.account) |
353 | 367 |
containers = get_content_splitted(r2) |
354 |
self.assertEqual(response['X-Account-Container-Count'], str(len(containers))) |
|
368 |
l = str(len(containers)) |
|
369 |
self.assertEqual(response['X-Account-Container-Count'], l) |
|
355 | 370 |
size = 0 |
356 | 371 |
for c in containers: |
357 | 372 |
r = self.get_container_meta(self.account, c) |
... | ... | |
394 | 409 |
self.assertEquals(self.containers[:2], containers) |
395 | 410 |
|
396 | 411 |
def test_list_with_marker(self): |
397 |
limit = 2
|
|
398 |
marker = 'bananas'
|
|
399 |
response = self.list_containers(self.account, limit=limit, marker=marker)
|
|
412 |
l = 2 |
|
413 |
m = 'bananas' |
|
414 |
response = self.list_containers(self.account, limit=l, marker=m)
|
|
400 | 415 |
containers = get_content_splitted(response) |
401 |
i = self.containers.index(marker) + 1
|
|
402 |
self.assertEquals(self.containers[i:(i+limit)], containers)
|
|
416 |
i = self.containers.index(m) + 1 |
|
417 |
self.assertEquals(self.containers[i:(i+l)], containers) |
|
403 | 418 |
|
404 |
marker = 'oranges'
|
|
405 |
response = self.list_containers(self.account, limit=limit, marker=marker)
|
|
419 |
m = 'oranges' |
|
420 |
response = self.list_containers(self.account, limit=l, marker=m)
|
|
406 | 421 |
containers = get_content_splitted(response) |
407 |
i = self.containers.index(marker) + 1
|
|
408 |
self.assertEquals(self.containers[i:(i+limit)], containers)
|
|
422 |
i = self.containers.index(m) + 1 |
|
423 |
self.assertEquals(self.containers[i:(i+l)], containers) |
|
409 | 424 |
|
410 | 425 |
#def test_extended_list(self): |
411 | 426 |
# self.list_containers(self.account, limit=3, format='xml') |
412 | 427 |
# self.list_containers(self.account, limit=3, format='json') |
413 | 428 |
|
414 | 429 |
def test_list_json_with_marker(self): |
415 |
limit = 2 |
|
416 |
marker = 'bananas' |
|
417 |
response = self.list_containers(self.account, limit=limit, marker=marker, format='json') |
|
430 |
l = 2 |
|
431 |
m = 'bananas' |
|
432 |
response = self.list_containers(self.account, limit=l, marker=m, |
|
433 |
format='json') |
|
418 | 434 |
containers = json.loads(response.content) |
419 | 435 |
self.assertEqual(containers[0]['name'], 'kiwis') |
420 | 436 |
self.assertEqual(containers[1]['name'], 'oranges') |
421 | 437 |
|
422 | 438 |
def test_list_xml_with_marker(self): |
423 |
limit = 2 |
|
424 |
marker = 'oranges' |
|
425 |
response = self.list_containers(self.account, limit=limit, marker=marker, format='xml') |
|
439 |
l = 2 |
|
440 |
m = 'oranges' |
|
441 |
response = self.list_containers(self.account, limit=l, marker=m, |
|
442 |
format='xml') |
|
426 | 443 |
xml = minidom.parseString(response.content) |
427 | 444 |
nodes = xml.getElementsByTagName('name') |
428 | 445 |
self.assertEqual(len(nodes), 1) |
... | ... | |
505 | 522 |
self.delete_container(self.account, c) |
506 | 523 |
|
507 | 524 |
def test_update_meta(self): |
508 |
meta = {'HTTP_X_ACCOUNT_META_TEST':'test', 'HTTP_X_ACCOUNT_META_TOST':'tost'} |
|
525 |
meta = {'HTTP_X_ACCOUNT_META_TEST':'test', |
|
526 |
'HTTP_X_ACCOUNT_META_TOST':'tost'} |
|
509 | 527 |
response = self.update_account_meta(self.account, **meta) |
510 | 528 |
response = self.get_account_meta(self.account) |
511 | 529 |
for k,v in meta.items(): |
... | ... | |
515 | 533 |
|
516 | 534 |
#def test_invalid_account_update_meta(self): |
517 | 535 |
# with AssertInvariant(self.get_account_meta, self.account): |
518 |
# meta = {'HTTP_X_ACCOUNT_META_TEST':'test', 'HTTP_X_ACCOUNT_META_TOST':'tost'} |
|
536 |
# meta = {'HTTP_X_ACCOUNT_META_TEST':'test', |
|
537 |
# 'HTTP_X_ACCOUNT_META_TOST':'tost'} |
|
519 | 538 |
# response = self.update_account_meta('non-existing-account', **meta) |
520 | 539 |
|
521 | 540 |
class ContainerHead(BaseTestCase): |
... | ... | |
590 | 609 |
'moms_birthday.jpg'] |
591 | 610 |
limit = 4 |
592 | 611 |
for m in markers: |
593 |
response = self.list_objects(self.account, self.container[0], limit=limit, marker=m) |
|
612 |
response = self.list_objects(self.account, self.container[0], |
|
613 |
limit=limit, marker=m) |
|
594 | 614 |
objects = get_content_splitted(response) |
595 | 615 |
l = [elem['name'] for elem in self.obj[:8]] |
596 | 616 |
l.sort() |
... | ... | |
600 | 620 |
self.assertEqual(objects, l[start:end]) |
601 | 621 |
|
602 | 622 |
def test_list_pseudo_hierarchical_folders(self): |
603 |
response = self.list_objects(self.account, self.container[1], prefix='photos', delimiter='/') |
|
623 |
response = self.list_objects(self.account, self.container[1], |
|
624 |
prefix='photos', delimiter='/') |
|
604 | 625 |
objects = get_content_splitted(response) |
605 |
self.assertEquals(['photos/animals/', 'photos/me.jpg', 'photos/plants/'], objects) |
|
626 |
self.assertEquals(['photos/animals/', 'photos/me.jpg', |
|
627 |
'photos/plants/'], objects) |
|
606 | 628 |
|
607 |
response = self.list_objects(self.account, self.container[1], prefix='photos/animals', delimiter='/') |
|
608 |
objects = get_content_splitted(response) |
|
609 |
self.assertEquals(['photos/animals/cats/', 'photos/animals/dogs/'], objects) |
|
629 |
response = self.list_objects(self.account, self.container[1], |
|
630 |
prefix='photos/animals', delimiter='/') |
|
631 |
objs = get_content_splitted(response) |
|
632 |
l = ['photos/animals/cats/', 'photos/animals/dogs/'] |
|
633 |
self.assertEquals(l, objs) |
|
610 | 634 |
|
611 |
response = self.list_objects(self.account, self.container[1], path='photos') |
|
635 |
response = self.list_objects(self.account, self.container[1], |
|
636 |
path='photos') |
|
612 | 637 |
objects = get_content_splitted(response) |
613 | 638 |
self.assertEquals(['photos/me.jpg'], objects) |
614 | 639 |
|
615 | 640 |
def test_extended_list_json(self): |
616 |
response = self.list_objects(self.account, self.container[1], format='json', limit=2, prefix='photos/animals', delimiter='/') |
|
641 |
response = self.list_objects(self.account, |
|
642 |
self.container[1], |
|
643 |
format='json', limit=2, |
|
644 |
prefix='photos/animals', |
|
645 |
delimiter='/') |
|
617 | 646 |
objects = json.loads(response.content) |
618 | 647 |
self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/') |
619 | 648 |
self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/') |
620 | 649 |
|
621 | 650 |
def test_extended_list_xml(self): |
622 |
response = self.list_objects(self.account, self.container[1], format='xml', limit=4, prefix='photos', delimiter='/') |
|
651 |
response = self.list_objects(self.account, self.container[1], |
|
652 |
format='xml', limit=4, prefix='photos', |
|
653 |
delimiter='/') |
|
623 | 654 |
xml = minidom.parseString(response.content) |
624 | 655 |
dirs = xml.getElementsByTagName('subdir') |
625 | 656 |
self.assertEqual(len(dirs), 2) |
... | ... | |
633 | 664 |
def test_list_using_meta(self): |
634 | 665 |
meta = {'HTTP_X_OBJECT_META_QUALITY':'aaa'} |
635 | 666 |
for o in self.obj[:2]: |
636 |
r = self.update_object_meta(self.account,
|
|
667 |
r = self.update_object(self.account, |
|
637 | 668 |
self.container[0], |
638 | 669 |
o['name'], |
639 | 670 |
**meta) |
640 | 671 |
meta = {'HTTP_X_OBJECT_META_STOCK':'true'} |
641 | 672 |
for o in self.obj[3:5]: |
642 |
r = self.update_object_meta(self.account,
|
|
673 |
r = self.update_object(self.account, |
|
643 | 674 |
self.container[0], |
644 | 675 |
o['name'], |
645 | 676 |
**meta) |
... | ... | |
729 | 760 |
|
730 | 761 |
#assert success |
731 | 762 |
self.assertEqual(r.status_code, 200) |
763 |
objlist = self.list_objects(self.account, self.container[0]) |
|
732 | 764 |
self.assertEqual(get_content_splitted(r), |
733 |
get_content_splitted(self.list_objects(self.account, |
|
734 |
self.container[0]))) |
|
765 |
get_content_splitted(objlist)) |
|
735 | 766 |
|
736 | 767 |
def test_if_unmodified_since_precondition_failed(self): |
737 | 768 |
t = datetime.datetime.utcnow() |
... | ... | |
765 | 796 |
response = self.create_container(self.account, self.containers[0]) |
766 | 797 |
if response.status_code == 201: |
767 | 798 |
response = self.list_containers(self.account) |
768 |
self.assertTrue(self.containers[0] in get_content_splitted(response)) |
|
799 |
content = get_content_splitted(response) |
|
800 |
self.assertTrue(self.containers[0] in content) |
|
769 | 801 |
r = self.get_container_meta(self.account, self.containers[0]) |
770 | 802 |
self.assertEqual(r.status_code, 204) |
771 | 803 |
|
772 | 804 |
def test_create_twice(self): |
773 | 805 |
response = self.create_container(self.account, self.containers[0]) |
774 | 806 |
if response.status_code == 201: |
775 |
self.assertTrue(self.create_container(self.account, self.containers[0]).status_code, 202) |
|
807 |
r = self.create_container(self.account, self.containers[0]) |
|
808 |
self.assertTrue(r.status_code, 202) |
|
776 | 809 |
|
777 | 810 |
class ContainerPost(BaseTestCase): |
778 | 811 |
def setUp(self): |
... | ... | |
789 | 822 |
def test_update_meta(self): |
790 | 823 |
meta = {'HTTP_X_CONTAINER_META_TEST':'test33', |
791 | 824 |
'HTTP_X_CONTAINER_META_TOST':'tost22'} |
792 |
response = self.update_container_meta(self.account, self.container, **meta) |
|
825 |
response = self.update_container_meta(self.account, self.container, |
|
826 |
**meta) |
|
793 | 827 |
response = self.get_container_meta(self.account, self.container) |
794 | 828 |
for k,v in meta.items(): |
795 | 829 |
key = '-'.join(elem.capitalize() for elem in k.split('_')[1:]) |
... | ... | |
859 | 893 |
self.objects[0]['meta']) |
860 | 894 |
#assert success |
861 | 895 |
self.assertEqual(r.status_code, 200) |
896 |
|
|
897 |
#assert content-type |
|
898 |
self.assertEqual(r['Content-Type'], |
|
899 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
862 | 900 |
|
863 | 901 |
def test_get_invalid(self): |
864 | 902 |
r = self.get_object(self.account, |
... | ... | |
877 | 915 |
#assert successful partial content |
878 | 916 |
self.assertEqual(r.status_code, 206) |
879 | 917 |
|
918 |
#assert content-type |
|
919 |
self.assertEqual(r['Content-Type'], |
|
920 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
921 |
|
|
880 | 922 |
#assert content length |
881 | 923 |
self.assertEqual(int(r['Content-Length']), 500) |
882 | 924 |
|
... | ... | |
894 | 936 |
#assert successful partial content |
895 | 937 |
self.assertEqual(r.status_code, 206) |
896 | 938 |
|
939 |
#assert content-type |
|
940 |
self.assertEqual(r['Content-Type'], |
|
941 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
942 |
|
|
897 | 943 |
#assert content length |
898 | 944 |
self.assertEqual(int(r['Content-Length']), 500) |
899 | 945 |
|
... | ... | |
912 | 958 |
#assert successful partial content |
913 | 959 |
self.assertEqual(r.status_code, 206) |
914 | 960 |
|
961 |
#assert content-type |
|
962 |
self.assertEqual(r['Content-Type'], |
|
963 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
964 |
|
|
915 | 965 |
#assert content length |
916 | 966 |
self.assertEqual(int(r['Content-Length']), 500) |
917 | 967 |
|
... | ... | |
1002 | 1052 |
#assert get success |
1003 | 1053 |
self.assertEqual(r.status_code, 200) |
1004 | 1054 |
|
1055 |
#assert content-type |
|
1056 |
self.assertEqual(r['Content-Type'], |
|
1057 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1058 |
|
|
1005 | 1059 |
#assert response content |
1006 | 1060 |
self.assertEqual(self.objects[0]['data'].strip(), r.content.strip()) |
1007 | 1061 |
|
... | ... | |
1015 | 1069 |
#assert get success |
1016 | 1070 |
self.assertEqual(r.status_code, 200) |
1017 | 1071 |
|
1072 |
#assert content-type |
|
1073 |
self.assertEqual(r['Content-Type'], |
|
1074 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1075 |
|
|
1018 | 1076 |
#assert response content |
1019 | 1077 |
self.assertEqual(self.objects[0]['data'].strip(), r.content.strip()) |
1020 | 1078 |
|
... | ... | |
1030 | 1088 |
#assert get success |
1031 | 1089 |
self.assertEqual(r.status_code, 200) |
1032 | 1090 |
|
1091 |
#assert content-type |
|
1092 |
self.assertEqual(r['Content-Type'], |
|
1093 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1094 |
|
|
1095 |
#assert content-type |
|
1096 |
self.assertEqual(r['Content-Type'], |
|
1097 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1098 |
|
|
1033 | 1099 |
#assert response content |
1034 | 1100 |
self.assertEqual(self.objects[0]['data'].strip(), r.content.strip()) |
1035 | 1101 |
|
... | ... | |
1053 | 1119 |
|
1054 | 1120 |
#assert get success |
1055 | 1121 |
self.assertEqual(r.status_code, 200) |
1122 |
|
|
1123 |
#assert content-type |
|
1124 |
self.assertEqual(r['Content-Type'], |
|
1125 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1056 | 1126 |
|
1057 | 1127 |
def test_if_none_match(self): |
1058 | 1128 |
#perform get with If-None-Match * |
... | ... | |
1098 | 1168 |
|
1099 | 1169 |
#assert get success |
1100 | 1170 |
self.assertEqual(r.status_code, 200) |
1171 |
|
|
1172 |
#assert content-type |
|
1173 |
self.assertEqual(r['Content-Type'], |
|
1174 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1101 | 1175 |
|
1102 | 1176 |
def test_if_modified_since_invalid_date(self): |
1103 | 1177 |
headers = {'HTTP_IF_MODIFIED_SINCE':''} |
... | ... | |
1108 | 1182 |
|
1109 | 1183 |
#assert get success |
1110 | 1184 |
self.assertEqual(r.status_code, 200) |
1185 |
|
|
1186 |
#assert content-type |
|
1187 |
self.assertEqual(r['Content-Type'], |
|
1188 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1111 | 1189 |
|
1112 | 1190 |
def test_if_not_modified_since(self): |
1113 | 1191 |
now = datetime.datetime.utcnow() |
... | ... | |
1136 | 1214 |
#assert success |
1137 | 1215 |
self.assertEqual(r.status_code, 200) |
1138 | 1216 |
self.assertEqual(self.objects[0]['data'], r.content) |
1217 |
|
|
1218 |
#assert content-type |
|
1219 |
self.assertEqual(r['Content-Type'], |
|
1220 |
self.objects[0]['meta']['HTTP_CONTENT_TYPE']) |
|
1139 | 1221 |
|
1140 | 1222 |
def test_if_unmodified_since_precondition_failed(self): |
1141 | 1223 |
t = datetime.datetime.utcnow() |
... | ... | |
1159 | 1241 |
self.assertEqual(r.status_code, 412) |
1160 | 1242 |
|
1161 | 1243 |
def test_hashes(self): |
1162 |
#block_size = 4 * 1024 * 1024 |
|
1163 |
block_size = 128 * 1024 |
|
1164 |
block_num = 2 |
|
1165 |
l = block_size * block_num + 1 |
|
1166 |
fname = 'largefile.txt' |
|
1244 |
l = 8388609 |
|
1245 |
fname = 'largefile' |
|
1167 | 1246 |
o = self.upload_random_data(self.account, |
1168 | 1247 |
self.containers[1], |
1169 | 1248 |
fname, |
... | ... | |
1173 | 1252 |
self.containers[1], |
1174 | 1253 |
fname, |
1175 | 1254 |
'json') |
1176 |
hashes = json.loads(r.content)['hashes'] |
|
1177 |
self.assertTrue(len(hashes), block_num + 1) |
|
1255 |
body = json.loads(r.content) |
|
1256 |
hashes = body['hashes'] |
|
1257 |
block_size = body['block_size'] |
|
1258 |
block_hash = body['block_hash'] |
|
1259 |
block_num = l/block_size == 0 and l/block_size or l/block_size + 1 |
|
1260 |
self.assertTrue(len(hashes), block_num) |
|
1178 | 1261 |
i = 0 |
1179 | 1262 |
for h in hashes: |
1180 | 1263 |
start = i * block_size |
1181 | 1264 |
end = (i + 1) * block_size |
1182 |
self.assertEqual(h, compute_block_hash(o['data'][start:end])) |
|
1265 |
hash = compute_block_hash(o['data'][start:end], block_hash) |
|
1266 |
self.assertEqual(h, hash) |
|
1183 | 1267 |
i += 1 |
1184 | 1268 |
|
1185 | 1269 |
class ObjectPut(BaseTestCase): |
... | ... | |
1194 | 1278 |
create_chunked_update_test_file(self.src, self.dest) |
1195 | 1279 |
|
1196 | 1280 |
def tearDown(self): |
1197 |
for o in get_content_splitted(self.list_objects(self.account, self.container)): |
|
1281 |
r = self.list_objects(self.account, self.container) |
|
1282 |
for o in get_content_splitted(r): |
|
1198 | 1283 |
self.delete_object(self.account, self.container, o) |
1199 | 1284 |
self.delete_container(self.account, self.container) |
1200 | 1285 |
|
... | ... | |
1211 | 1296 |
'HTTP_X_OBJECT_MANIFEST':123, |
1212 | 1297 |
'HTTP_X_OBJECT_META_TEST':'test1' |
1213 | 1298 |
} |
1214 |
meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(fullpath) |
|
1299 |
type, enc = mimetypes.guess_type(fullpath) |
|
1300 |
meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text' |
|
1301 |
if enc: |
|
1302 |
meta['HTTP_CONTENT_ENCODING'] = enc |
|
1215 | 1303 |
r = self.upload_object(self.account, |
1216 | 1304 |
self.container, |
1217 | 1305 |
filename, |
... | ... | |
1221 | 1309 |
self.assertEqual(r.status_code, 201) |
1222 | 1310 |
r = self.get_object_meta(self.account, self.container, filename) |
1223 | 1311 |
self.assertTrue(r['X-Object-Meta-Test']) |
1224 |
self.assertEqual(r['X-Object-Meta-Test'], meta['HTTP_X_OBJECT_META_TEST']) |
|
1312 |
self.assertEqual(r['X-Object-Meta-Test'], |
|
1313 |
meta['HTTP_X_OBJECT_META_TEST']) |
|
1225 | 1314 |
|
1226 | 1315 |
#assert uploaded content |
1227 | 1316 |
r = self.get_object(self.account, self.container, filename) |
... | ... | |
1237 | 1326 |
'HTTP_X_OBJECT_MANIFEST':123, |
1238 | 1327 |
'HTTP_X_OBJECT_META_TEST':'test1' |
1239 | 1328 |
} |
1240 |
meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(fullpath) |
|
1329 |
type, enc = mimetypes.guess_type(fullpath) |
|
1330 |
meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text' |
|
1331 |
if enc: |
|
1332 |
meta['HTTP_CONTENT_ENCODING'] = enc |
|
1241 | 1333 |
r = self.upload_object(self.account, |
1242 | 1334 |
self.container, |
1243 | 1335 |
filename, |
... | ... | |
1251 | 1343 |
f = open(self.dest, 'r') |
1252 | 1344 |
data = f.read() |
1253 | 1345 |
meta = {} |
1254 |
meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(objname) |
|
1346 |
type, enc = mimetypes.guess_type(self.dest) |
|
1347 |
meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text' |
|
1348 |
if enc: |
|
1349 |
meta['HTTP_CONTENT_ENCODING'] = enc |
|
1255 | 1350 |
meta.update({'HTTP_TRANSFER_ENCODING':'chunked'}) |
1256 | 1351 |
r = self.upload_object(self.account, |
1257 | 1352 |
self.container, |
... | ... | |
1287 | 1382 |
self.delete_container(self.account, c) |
1288 | 1383 |
|
1289 | 1384 |
def test_copy(self): |
1290 |
with AssertInvariant(self.get_object_meta, self.account, self.containers[0], self.obj['name']): |
|
1385 |
with AssertInvariant(self.get_object_meta, self.account, |
|
1386 |
self.containers[0], self.obj['name']): |
|
1291 | 1387 |
#perform copy |
1292 | 1388 |
meta = {'HTTP_X_OBJECT_META_TEST':'testcopy'} |
1293 | 1389 |
src_path = os.path.join('/', self.containers[0], self.obj['name']) |
... | ... | |
1310 | 1406 |
self.assertEqual(r['ETag'], self.obj['hash']) |
1311 | 1407 |
|
1312 | 1408 |
#assert src object still exists |
1313 |
r = self.get_object_meta(self.account, self.containers[0], self.obj['name']) |
|
1409 |
r = self.get_object_meta(self.account, self.containers[0], |
|
1410 |
self.obj['name']) |
|
1314 | 1411 |
self.assertEqual(r.status_code, 204) |
1315 | 1412 |
|
1316 | 1413 |
def test_copy_from_different_container(self): |
... | ... | |
1335 | 1432 |
self.assertTrue(r['X-Object-Meta-Test'], 'testcopy') |
1336 | 1433 |
|
1337 | 1434 |
#assert src object still exists |
1338 |
r = self.get_object_meta(self.account, self.containers[0], self.obj['name']) |
|
1435 |
r = self.get_object_meta(self.account, self.containers[0], |
|
1436 |
self.obj['name']) |
|
1339 | 1437 |
self.assertEqual(r.status_code, 204) |
1340 | 1438 |
|
1341 | 1439 |
def test_copy_invalid(self): |
... | ... | |
1379 | 1477 |
self.assertTrue(r['X-Object-Meta-Test'], 'testcopy') |
1380 | 1478 |
|
1381 | 1479 |
#assert src object no more exists |
1382 |
r = self.get_object_meta(self.account, self.containers[0], self.obj['name']) |
|
1480 |
r = self.get_object_meta(self.account, self.containers[0], |
|
1481 |
self.obj['name']) |
|
1383 | 1482 |
self.assertItemNotFound(r) |
1384 | 1483 |
|
1385 | 1484 |
class ObjectPost(BaseTestCase): |
... | ... | |
1399 | 1498 |
self.delete_object(self.account, c, o) |
1400 | 1499 |
self.delete_container(self.account, c) |
1401 | 1500 |
|
1402 |
def test_update(self): |
|
1501 |
def test_update_meta(self):
|
|
1403 | 1502 |
#perform update metadata |
1404 | 1503 |
more = {'HTTP_X_OBJECT_META_FOO':'foo', |
1405 | 1504 |
'HTTP_X_OBJECT_META_BAR':'bar'} |
1406 |
r = self.update_object_meta(self.account,
|
|
1505 |
r = self.update_object(self.account, |
|
1407 | 1506 |
self.containers[0], |
1408 | 1507 |
self.obj['name'], |
1409 | 1508 |
**more) |
... | ... | |
1411 | 1510 |
self.assertEqual(r.status_code, 202) |
1412 | 1511 |
|
1413 | 1512 |
#assert old metadata are still there |
1414 |
r = self.get_object_meta(self.account, self.containers[0], self.obj['name']) |
|
1513 |
r = self.get_object_meta(self.account, self.containers[0], |
|
1514 |
self.obj['name']) |
|
1415 | 1515 |
self.assertTrue('X-Object-Meta-Test' not in r.items()) |
1416 | 1516 |
|
1417 | 1517 |
#assert new metadata have been updated |
... | ... | |
1420 | 1520 |
self.assertTrue(r[key]) |
1421 | 1521 |
self.assertTrue(r[key], v) |
1422 | 1522 |
|
1523 |
def test_update_object(self, |
|
1524 |
first_byte_pos=0, |
|
1525 |
last_byte_pos=499, |
|
1526 |
instance_length = True, |
|
1527 |
content_length = 500): |
|
1528 |
l = len(self.obj['data']) |
|
1529 |
if instance_length: |
|
1530 |
range = 'bytes %d-%d/%d' %(first_byte_pos, |
|
1531 |
last_byte_pos, |
|
1532 |
l) |
|
1533 |
else: |
|
1534 |
range = 'bytes %d-%d/*' %(first_byte_pos, |
|
1535 |
last_byte_pos) |
|
1536 |
partial = last_byte_pos - first_byte_pos + 1 |
|
1537 |
data = get_random_data(partial) |
|
1538 |
more = {'HTTP_CONTENT_RANGE':range} |
|
1539 |
if content_length: |
|
1540 |
more.update({'CONTENT_LENGTH':'%s' % content_length}) |
|
1541 |
|
|
1542 |
r = self.update_object(self.account, |
|
1543 |
self.containers[0], |
|
1544 |
self.obj['name'], |
|
1545 |
data, |
|
1546 |
'application/octet-stream', |
|
1547 |
**more) |
|
1548 |
|
|
1549 |
if partial < 0 or (instance_length and l <= last_byte_pos): |
|
1550 |
self.assertEqual(r.status_code, 202) |
|
1551 |
elif content_length and content_length != partial: |
|
1552 |
self.assertEqual(r.status_code, 400) |
|
1553 |
else: |
|
1554 |
self.assertEqual(r.status_code, 204) |
|
1555 |
|
|
1556 |
#check modified object |
|
1557 |
r = self.get_object(self.account, |
|
1558 |
self.containers[0], |
|
1559 |
self.obj['name']) |
|
1560 |
self.assertEqual(r.content[0:partial], data) |
|
1561 |
self.assertEqual(r.content[partial:l], self.obj['data'][partial:l]) |
|
1562 |
|
|
1563 |
def test_update_object_no_content_length(self): |
|
1564 |
self.test_update_object(content_length = None) |
|
1565 |
|
|
1566 |
def test_update_object_invalid_content_length(self): |
|
1567 |
with AssertContentInvariant(self.get_object, self.account, self.containers[0], |
|
1568 |
self.obj['name']): |
|
1569 |
self.test_update_object(content_length = 1000) |
|
1570 |
|
|
1571 |
def test_update_object_with_unknown_instance_length(self): |
|
1572 |
self.test_update_object(instance_length = False) |
|
1573 |
|
|
1574 |
def test_update_object_invalid_range(self): |
|
1575 |
with AssertContentInvariant(self.get_object, self.account, self.containers[0], |
|
1576 |
self.obj['name']): |
|
1577 |
self.test_update_object(499, 0, True) |
|
1578 |
|
|
1579 |
def test_update_object_invalid_range_and_length(self): |
|
1580 |
with AssertContentInvariant(self.get_object, self.account, self.containers[0], |
|
1581 |
self.obj['name']): |
|
1582 |
self.test_update_object(499, 0, True, -1) |
|
1583 |
|
|
1584 |
def test_update_object_invalid_range_with_no_content_length(self): |
|
1585 |
with AssertContentInvariant(self.get_object, self.account, self.containers[0], |
|
1586 |
self.obj['name']): |
|
1587 |
self.test_update_object(499, 0, True, content_length = None) |
|
1588 |
|
|
1589 |
def test_update_object_out_of_limits(self): |
|
1590 |
with AssertContentInvariant(self.get_object, self.account, self.containers[0], |
|
1591 |
self.obj['name']): |
|
1592 |
l = len(self.obj['data']) |
|
1593 |
self.test_update_object(0, l+1, True) |
|
1594 |
|
|
1595 |
def test_append(self): |
|
1596 |
data = get_random_data(500) |
|
1597 |
more = {'CONTENT_LENGTH':'500', |
|
1598 |
'HTTP_CONTENT_RANGE':'bytes */*'} |
|
1599 |
|
|
1600 |
r = self.update_object(self.account, |
|
1601 |
self.containers[0], |
|
1602 |
self.obj['name'], |
|
1603 |
data, |
|
1604 |
'application/octet-stream', |
|
1605 |
**more) |
|
1606 |
|
|
1607 |
self.assertEqual(r.status_code, 204) |
|
1608 |
|
|
1609 |
r = self.get_object(self.account, |
|
1610 |
self.containers[0], |
|
1611 |
self.obj['name']) |
|
1612 |
self.assertEqual(len(r.content), len(self.obj['data']) + 500) |
|
1613 |
|
|
1614 |
#def test_update_with_chunked_transfer(self): |
|
1615 |
# linenum = 5 |
|
1616 |
# data = create_random_chunked_data(linenum) |
|
1617 |
# print data |
|
1618 |
# first_byte_pos=0, |
|
1619 |
# last_byte_pos=499, |
|
1620 |
# instance_length = True, |
|
1621 |
# content_length = 500 |
|
1622 |
# l = len(self.obj['data']) |
|
1623 |
# meta = {'HTTP_TRANSFER_ENCODING':'chunked', |
|
1624 |
# 'HTTP_CONTENT_RANGE':'bytes 0-499/%d' %l} |
|
1625 |
# r = self.update_object(self.account, |
|
1626 |
# self.containers[0], |
|
1627 |
# self.obj['name'], |
|
1628 |
# data, |
|
1629 |
# 'application/octet-stream', |
|
1630 |
# **meta) |
|
1631 |
# print r.request, r.status_code, r |
|
1632 |
|
|
1423 | 1633 |
class ObjectDelete(BaseTestCase): |
1424 | 1634 |
def setUp(self): |
1425 | 1635 |
BaseTestCase.setUp(self) |
... | ... | |
1439 | 1649 |
|
1440 | 1650 |
def test_delete(self): |
1441 | 1651 |
#perform delete object |
1442 |
r = self.delete_object(self.account, self.containers[0], self.obj['name']) |
|
1652 |
r = self.delete_object(self.account, self.containers[0], |
|
1653 |
self.obj['name']) |
|
1443 | 1654 |
|
1444 | 1655 |
#assert success |
1445 | 1656 |
self.assertEqual(r.status_code, 204) |
1446 | 1657 |
|
1447 | 1658 |
def test_delete_invalid(self): |
1448 | 1659 |
#perform delete object |
1449 |
r = self.delete_object(self.account, self.containers[1], self.obj['name']) |
|
1660 |
r = self.delete_object(self.account, self.containers[1], |
|
1661 |
self.obj['name']) |
|
1450 | 1662 |
|
1451 | 1663 |
#assert failure |
1452 | 1664 |
self.assertItemNotFound(r) |
... | ... | |
1465 | 1677 |
items = self.callable(*self.args, **self.kwargs).items() |
1466 | 1678 |
assert self.items == items |
1467 | 1679 |
|
1680 |
class AssertContentInvariant(object): |
|
1681 |
def __init__(self, callable, *args, **kwargs): |
|
1682 |
self.callable = callable |
|
1683 |
self.args = args |
|
1684 |
self.kwargs = kwargs |
|
1685 |
|
|
1686 |
def __enter__(self): |
|
1687 |
self.content = self.callable(*self.args, **self.kwargs).content |
|
1688 |
return self.content |
|
1689 |
|
|
1690 |
def __exit__(self, type, value, tb): |
|
1691 |
content = self.callable(*self.args, **self.kwargs).content |
|
1692 |
assert self.content == content |
|
1693 |
|
|
1468 | 1694 |
def get_content_splitted(response): |
1469 | 1695 |
if response: |
1470 | 1696 |
return response.content.split('\n') |
... | ... | |
1475 | 1701 |
md5.update(data) |
1476 | 1702 |
return md5.hexdigest().lower() |
1477 | 1703 |
|
1478 |
def compute_block_hash(data): |
|
1479 |
h = hashlib.new(backend.hash_algorithm)
|
|
1704 |
def compute_block_hash(data, algorithm):
|
|
1705 |
h = hashlib.new(algorithm) |
|
1480 | 1706 |
h.update(data.rstrip('\x00')) |
1481 | 1707 |
return h.hexdigest() |
1482 | 1708 |
|
... | ... | |
1492 | 1718 |
fw.write(hex(0)) |
1493 | 1719 |
fw.write('\r\n') |
1494 | 1720 |
|
1721 |
def create_random_chunked_data(rows): |
|
1722 |
i = 0 |
|
1723 |
out = [] |
|
1724 |
while i < rows: |
|
1725 |
data = get_random_data(random.randint(1, 100)) |
|
1726 |
out.append(hex(len(data))) |
|
1727 |
out.append(data) |
|
1728 |
i+=1 |
|
1729 |
out.append(hex(0)) |
|
1730 |
out.append('\r\n') |
|
1731 |
return '\r\n'.join(out) |
|
1732 |
|
|
1733 |
def get_random_data(length): |
|
1734 |
char_set = string.ascii_uppercase + string.digits |
|
1735 |
return ''.join(random.choice(char_set) for x in range(length)) |
|
1736 |
|
|
1495 | 1737 |
o_names = ['kate.jpg', |
1496 | 1738 |
'kate_beckinsale.jpg', |
1497 | 1739 |
'How To Win Friends And Influence People.pdf', |
Also available in: Unified diff