4 # Copyright 2011-2012 GRNET S.A. All rights reserved.
6 # Redistribution and use in source and binary forms, with or
7 # without modification, are permitted provided that the following
10 # 1. Redistributions of source code must retain the above
11 # copyright notice, this list of conditions and the following
14 # 2. Redistributions in binary form must reproduce the above
15 # copyright notice, this list of conditions and the following
16 # disclaimer in the documentation and/or other materials
17 # provided with the distribution.
19 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 # POSSIBILITY OF SUCH DAMAGE.
32 # The views and conclusions contained in the software and
33 # documentation are those of the authors and should not be
34 # interpreted as representing official policies, either expressed
35 # or implied, of GRNET S.A.
37 from pithos.tools.lib.client import Pithos_Client, Fault
38 from pithos.tools.lib.util import get_user, get_auth, get_url
40 from xml.dom import minidom
41 from StringIO import StringIO
42 from hashlib import new as newhasher
43 from binascii import hexlify
44 from httplib import HTTPConnection, HTTPSConnection
45 from urlparse import urlparse
58 DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
59 "%A, %d-%b-%y %H:%M:%S GMT",
60 "%a, %d %b %Y %H:%M:%S GMT"]
73 class BaseTestCase(unittest.TestCase):
74 #TODO unauthorized request
76 self.client = Pithos_Client(get_url(), get_auth(), get_user())
78 self.invalid_client = Pithos_Client(get_url(), get_auth(), 'invalid')
80 #keep track of initial account groups
81 self.initial_groups = self.client.retrieve_account_groups()
83 #keep track of initial account meta
84 self.initial_meta = self.client.retrieve_account_metadata(restricted=True)
92 'x_container_policy'),
100 self.return_codes = (400, 401, 403, 404, 503,)
103 #delete additionally created meta
105 for m in self.client.retrieve_account_metadata(restricted=True):
106 if m not in self.initial_meta:
108 self.client.delete_account_metadata(l)
110 #delete additionally created groups
112 for g in self.client.retrieve_account_groups():
113 if g not in self.initial_groups:
115 self.client.unset_account_groups(l)
116 self._clean_account()
118 def _clean_account(self):
119 for c in self.client.list_containers():
120 self.client.delete_container(c, delimiter='/')
121 self.client.delete_container(c)
123 def assert_status(self, status, codes):
124 l = [elem for elem in self.return_codes]
125 if type(codes) == types.ListType:
129 self.assertTrue(status in l)
131 def assert_extended(self, data, format, type, size=10000):
133 self._assert_xml(data, type, size)
134 elif format == 'json':
135 self._assert_json(data, type, size)
137 def _assert_json(self, data, type, size):
138 convert = lambda s: s.lower()
139 info = [convert(elem) for elem in self.extended[type]]
140 self.assertTrue(len(data) <= size)
143 if 'subdir' in i.keys():
145 self.assertTrue(item in i.keys())
147 def _assert_xml(self, data, type, size):
148 convert = lambda s: s.lower()
149 info = [convert(elem) for elem in self.extended[type]]
151 info.remove('content_encoding')
155 entities = xml.getElementsByTagName(type)
156 self.assertTrue(len(entities) <= size)
159 self.assertTrue(e.getElementsByTagName(item))
161 def assert_raises_fault(self, status, callableObj, *args, **kwargs):
163 asserts that a Fault with a specific status is raised
164 when callableObj is called with the specific arguments
167 r = callableObj(*args, **kwargs)
168 self.fail('Should never reach here')
170 if type(status) == types.ListType:
171 self.failUnless(f.status in status)
173 self.failUnless(f.status == status)
175 def assert_not_raises_fault(self, status, callableObj, *args, **kwargs):
177 asserts that a Fault with a specific status is not raised
178 when callableObj is called with the specific arguments
181 r = callableObj(*args, **kwargs)
183 self.failIfEqual(f.status, status)
185 def assert_container_exists(self, container):
187 asserts the existence of a container
190 self.client.retrieve_container_metadata(container)
192 self.failIf(f.status == 404)
194 def assert_container_not_exists(self, container):
196 asserts there is no such a container
198 self.assert_raises_fault(404, self.client.retrieve_container_metadata,
201 def assert_object_exists(self, container, object):
203 asserts the existence of an object
206 self.client.retrieve_object_metadata(container, object)
208 self.failIf(f.status == 404)
210 def assert_object_not_exists(self, container, object):
212 asserts there is no such an object
214 self.assert_raises_fault(404, self.client.retrieve_object_metadata,
217 def assert_versionlist_structure(self, versionlist):
218 self.assertTrue(type(versionlist) == types.ListType)
219 for elem in versionlist:
220 self.assertTrue(type(elem) == types.ListType)
221 self.assertEqual(len(elem), 2)
223 def upload_random_data(self, container, name, length=1024, type=None,
225 data = get_random_data(length)
226 return self.upload_data(container, name, data, type, enc, **meta)
228 def upload_data(self, container, name, data, type=None, enc=None, etag=None,
234 obj['hash'] = compute_md5_hash(obj['data'])
237 args['etag'] = etag if etag else obj['hash']
240 guess = mimetypes.guess_type(name)
241 type = type if type else guess[0]
242 enc = enc if enc else guess[1]
245 args['content_type'] = type if type else 'plain/text'
246 args['content_encoding'] = enc if enc else None
250 path = '/%s/%s' % (container, name)
251 self.client.create_object(container, name, f=StringIO(obj['data']),
258 class AccountHead(BaseTestCase):
260 BaseTestCase.setUp(self)
261 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
262 for item in self.containers:
263 self.client.create_container(item)
266 self.client.update_account_metadata(**meta)
267 #self.updated_meta = self.initial_meta.update(meta)
269 def test_get_account_meta(self):
270 meta = self.client.retrieve_account_metadata()
272 containers = self.client.list_containers()
273 l = str(len(containers))
274 self.assertEqual(meta['x-account-container-count'], l)
277 m = self.client.retrieve_container_metadata(c)
278 size = size + int(m['x-container-bytes-used'])
279 self.assertEqual(meta['x-account-bytes-used'], str(size))
281 def test_get_account_403(self):
282 self.assert_raises_fault(403,
283 self.invalid_client.retrieve_account_metadata)
285 def test_get_account_meta_until(self):
286 t = datetime.datetime.utcnow()
287 past = t - datetime.timedelta(minutes=-15)
288 past = int(_time.mktime(past.timetuple()))
290 meta = {'premium':True}
291 self.client.update_account_metadata(**meta)
292 meta = self.client.retrieve_account_metadata(restricted=True,
294 self.assertTrue('premium' not in meta)
296 meta = self.client.retrieve_account_metadata(restricted=True)
297 self.assertTrue('premium' in meta)
299 def test_get_account_meta_until_invalid_date(self):
300 meta = {'premium':True}
301 self.client.update_account_metadata(**meta)
302 meta = self.client.retrieve_account_metadata(restricted=True,
304 self.assertTrue('premium' in meta)
306 class AccountGet(BaseTestCase):
308 BaseTestCase.setUp(self)
309 #create some containers
310 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
311 for item in self.containers:
312 self.client.create_container(item)
316 containers = self.client.list_containers()
317 self.assertEquals(self.containers, containers)
319 def test_list_403(self):
320 self.assert_raises_fault(403, self.invalid_client.list_containers)
322 def test_list_with_limit(self):
324 containers = self.client.list_containers(limit=limit)
325 self.assertEquals(len(containers), limit)
326 self.assertEquals(self.containers[:2], containers)
328 def test_list_with_marker(self):
331 containers = self.client.list_containers(limit=l, marker=m)
332 i = self.containers.index(m) + 1
333 self.assertEquals(self.containers[i:(i+l)], containers)
336 containers = self.client.list_containers(limit=l, marker=m)
337 i = self.containers.index(m) + 1
338 self.assertEquals(self.containers[i:(i+l)], containers)
340 def test_list_json_with_marker(self):
343 containers = self.client.list_containers(limit=l, marker=m, format='json')
344 self.assert_extended(containers, 'json', 'container', l)
345 self.assertEqual(containers[0]['name'], 'kiwis')
346 self.assertEqual(containers[1]['name'], 'oranges')
348 def test_list_xml_with_marker(self):
351 xml = self.client.list_containers(limit=l, marker=m, format='xml')
352 self.assert_extended(xml, 'xml', 'container', l)
353 nodes = xml.getElementsByTagName('name')
354 self.assertEqual(len(nodes), 1)
355 self.assertEqual(nodes[0].childNodes[0].data, 'pears')
357 def test_if_modified_since(self):
358 t = datetime.datetime.utcnow()
359 t2 = t - datetime.timedelta(minutes=10)
362 self.client.create_container('dummy')
364 for f in DATE_FORMATS:
365 past = t2.strftime(f)
367 c = self.client.list_containers(if_modified_since=past)
368 self.assertEqual(len(c), len(self.containers) + 1)
370 self.failIf(f.status == 304) #fail if not modified
373 def test_if_modified_since_invalid_date(self):
374 c = self.client.list_containers(if_modified_since='')
375 self.assertEqual(len(c), len(self.containers))
377 def test_if_not_modified_since(self):
378 now = datetime.datetime.utcnow()
379 since = now + datetime.timedelta(1)
381 for f in DATE_FORMATS:
382 args = {'if_modified_since':'%s' %since.strftime(f)}
385 self.assert_raises_fault(304, self.client.list_containers, **args)
387 def test_if_unmodified_since(self):
388 now = datetime.datetime.utcnow()
389 since = now + datetime.timedelta(1)
391 for f in DATE_FORMATS:
392 c = self.client.list_containers(if_unmodified_since=since.strftime(f))
395 self.assertEqual(self.containers, c)
397 def test_if_unmodified_since_precondition_failed(self):
398 t = datetime.datetime.utcnow()
399 t2 = t - datetime.timedelta(minutes=10)
402 self.client.create_container('dummy')
404 for f in DATE_FORMATS:
405 past = t2.strftime(f)
407 args = {'if_unmodified_since':'%s' %past}
409 #assert precondition failed
410 self.assert_raises_fault(412, self.client.list_containers, **args)
412 class AccountPost(BaseTestCase):
414 BaseTestCase.setUp(self)
415 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
416 for item in self.containers:
417 self.client.create_container(item)
420 self.client.update_account_metadata(**meta)
421 self.updated_meta = self.initial_meta.update(meta)
423 def test_update_meta(self):
424 with AssertMappingInvariant(self.client.retrieve_account_groups):
425 meta = {'test':'test', 'tost':'tost'}
426 self.client.update_account_metadata(**meta)
428 meta.update(self.initial_meta)
429 self.assertEqual(meta,
430 self.client.retrieve_account_metadata(
433 def test_invalid_account_update_meta(self):
434 meta = {'test':'test', 'tost':'tost'}
435 self.assert_raises_fault(403,
436 self.invalid_client.update_account_metadata,
439 def test_reset_meta(self):
440 with AssertMappingInvariant(self.client.retrieve_account_groups):
441 meta = {'test':'test', 'tost':'tost'}
442 self.client.update_account_metadata(**meta)
444 meta = {'test':'test33'}
445 self.client.reset_account_metadata(**meta)
447 self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
449 def test_delete_meta(self):
450 with AssertMappingInvariant(self.client.retrieve_account_groups):
451 meta = {'test':'test', 'tost':'tost'}
452 self.client.update_account_metadata(**meta)
454 self.client.delete_account_metadata(meta.keys())
456 account_meta = self.client.retrieve_account_metadata(restricted=True)
458 self.assertTrue(m not in account_meta.keys())
460 def test_set_account_groups(self):
461 with AssertMappingInvariant(self.client.retrieve_account_metadata):
462 groups = {'pithosdev':'verigak,gtsouk,chazapis'}
463 self.client.set_account_groups(**groups)
465 self.assertEqual(set(groups['pithosdev']),
466 set(self.client.retrieve_account_groups()['pithosdev']))
468 more_groups = {'clientsdev':'pkanavos,mvasilak'}
469 self.client.set_account_groups(**more_groups)
471 groups.update(more_groups)
472 self.assertEqual(set(groups['clientsdev']),
473 set(self.client.retrieve_account_groups()['clientsdev']))
475 def test_reset_account_groups(self):
476 with AssertMappingInvariant(self.client.retrieve_account_metadata):
477 groups = {'pithosdev':'verigak,gtsouk,chazapis',
478 'clientsdev':'pkanavos,mvasilak'}
479 self.client.set_account_groups(**groups)
481 self.assertEqual(set(groups['pithosdev'].split(',')),
482 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
483 self.assertEqual(set(groups['clientsdev'].split(',')),
484 set(self.client.retrieve_account_groups()['clientsdev'].split(',')))
486 groups = {'pithosdev':'verigak,gtsouk,chazapis,papagian'}
487 self.client.reset_account_groups(**groups)
489 self.assertEqual(set(groups['pithosdev'].split(',')),
490 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
492 def test_delete_account_groups(self):
493 with AssertMappingInvariant(self.client.retrieve_account_metadata):
494 groups = {'pithosdev':'verigak,gtsouk,chazapis',
495 'clientsdev':'pkanavos,mvasilak'}
496 self.client.set_account_groups(**groups)
498 self.client.unset_account_groups(groups.keys())
500 self.assertEqual({}, self.client.retrieve_account_groups())
502 class ContainerHead(BaseTestCase):
504 BaseTestCase.setUp(self)
505 self.container = 'apples'
506 self.client.create_container(self.container)
508 def test_get_meta(self):
509 meta = {'trash':'true'}
510 t1 = datetime.datetime.utcnow()
511 o = self.upload_random_data(self.container, o_names[0], **meta)
513 headers = self.client.retrieve_container_metadata(self.container)
514 self.assertEqual(headers['x-container-object-count'], '1')
515 self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
516 t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
518 threashold = datetime.timedelta(seconds=1)
519 self.assertTrue(delta < threashold)
520 self.assertTrue(headers['x-container-object-meta'])
521 self.assertTrue('Trash' in headers['x-container-object-meta'])
523 class ContainerGet(BaseTestCase):
525 BaseTestCase.setUp(self)
526 self.container = ['pears', 'apples']
527 for c in self.container:
528 self.client.create_container(c)
530 for o in o_names[:8]:
531 self.obj.append(self.upload_random_data(self.container[0], o))
532 for o in o_names[8:]:
533 self.obj.append(self.upload_random_data(self.container[1], o))
535 def test_list_shared(self):
536 self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
537 objs = self.client.list_objects(self.container[0], shared=True)
538 self.assertEqual(objs, [self.obj[0]['name']])
540 # create child object
541 self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
542 objs = self.client.list_objects(self.container[0], shared=True)
543 self.assertEqual(objs, [self.obj[0]['name']])
546 self.client.create_folder(self.container[1], 'folder')
547 self.client.share_object(self.container[1], 'folder', ('*',))
548 self.upload_random_data(self.container[1], 'folder/object')
549 objs = self.client.list_objects(self.container[1], shared=True)
550 self.assertEqual(objs, ['folder', 'folder/object'])
552 def test_list_public(self):
553 self.client.publish_object(self.container[0], self.obj[0]['name'])
554 objs = self.client.list_objects(self.container[0], public=True)
555 self.assertEqual(objs, [self.obj[0]['name']])
557 # create child object
558 self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
559 objs = self.client.list_objects(self.container[0], public=True)
560 self.assertEqual(objs, [self.obj[0]['name']])
563 self.client.create_folder(self.container[1], 'folder')
564 self.client.publish_object(self.container[1], 'folder')
565 self.upload_random_data(self.container[1], 'folder/object')
566 objs = self.client.list_objects(self.container[1], public=True)
567 self.assertEqual(objs, ['folder'])
569 def test_list_shared_public(self):
570 self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
571 self.client.publish_object(self.container[0], self.obj[1]['name'])
572 objs = self.client.list_objects(self.container[0], shared=True, public=True)
573 self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
575 # create child object
576 self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
577 self.upload_random_data(self.container[0], strnextling(self.obj[1]['name']))
578 objs = self.client.list_objects(self.container[0], shared=True, public=True)
579 self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
582 self.client.create_folder(self.container[1], 'folder1')
583 self.client.share_object(self.container[1], 'folder1', ('*',))
584 self.upload_random_data(self.container[1], 'folder1/object')
585 self.client.create_folder(self.container[1], 'folder2')
586 self.client.publish_object(self.container[1], 'folder2')
587 o = self.upload_random_data(self.container[1], 'folder2/object')
588 objs = self.client.list_objects(self.container[1], shared=True, public=True)
589 self.assertEqual(objs, ['folder1', 'folder1/object', 'folder2'])
591 def test_list_objects(self):
592 objects = self.client.list_objects(self.container[0])
593 l = [elem['name'] for elem in self.obj[:8]]
595 self.assertEqual(objects, l)
597 def test_list_objects_containing_slash(self):
598 self.client.create_container('test')
599 self.upload_random_data('test', '/objectname')
601 objects = self.client.list_objects('test')
602 self.assertEqual(objects, ['/objectname'])
604 objects = self.client.list_objects('test', format='json')
605 self.assertEqual(objects[0]['name'], '/objectname')
607 objects = self.client.list_objects('test', format='xml')
608 self.assert_extended(objects, 'xml', 'object')
609 node_name = objects.getElementsByTagName('name')[0]
610 self.assertEqual(node_name.firstChild.data, '/objectname')
612 def test_list_objects_with_limit_marker(self):
613 objects = self.client.list_objects(self.container[0], limit=2)
614 l = [elem['name'] for elem in self.obj[:8]]
616 self.assertEqual(objects, l[:2])
618 markers = ['How To Win Friends And Influence People.pdf',
622 objects = self.client.list_objects(self.container[0], limit=limit,
624 l = [elem['name'] for elem in self.obj[:8]]
626 start = l.index(m) + 1
628 end = end if len(l) >= end else len(l)
629 self.assertEqual(objects, l[start:end])
632 def _test_list_limit_exceeds(self):
633 self.client.create_container('pithos')
635 for i in range(10001):
636 self.client.create_zero_length_object('pithos', i)
638 self.assertEqual(10000, len(self.client.list_objects('pithos')))
640 def test_list_empty_params(self):
641 objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
643 objects = objects.strip().split('\n')
644 self.assertEqual(objects,
645 self.client.list_objects(self.container[0]))
647 def test_list_pseudo_hierarchical_folders(self):
648 objects = self.client.list_objects(self.container[1], prefix='photos',
650 self.assertEquals(['photos/animals/', 'photos/me.jpg',
651 'photos/plants/'], objects)
653 objects = self.client.list_objects(self.container[1],
654 prefix='photos/animals',
656 l = ['photos/animals/cats/', 'photos/animals/dogs/']
657 self.assertEquals(l, objects)
659 objects = self.client.list_objects(self.container[1], path='photos')
660 self.assertEquals(['photos/me.jpg'], objects)
662 def test_extended_list_json(self):
663 objects = self.client.list_objects(self.container[1], format='json',
664 limit=2, prefix='photos/animals',
666 self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
667 self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
669 def test_extended_list_xml(self):
670 xml = self.client.list_objects(self.container[1], format='xml', limit=4,
671 prefix='photos', delimiter='/')
672 self.assert_extended(xml, 'xml', 'object', size=4)
673 dirs = xml.getElementsByTagName('subdir')
674 self.assertEqual(len(dirs), 2)
675 self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
676 self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
678 objects = xml.getElementsByTagName('name')
679 self.assertEqual(len(objects), 1)
680 self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
682 def test_list_meta_double_matching(self):
683 meta = {'quality':'aaa', 'stock':'true'}
684 self.client.update_object_metadata(self.container[0],
685 self.obj[0]['name'], **meta)
686 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
687 self.assertEqual(len(obj), 1)
688 self.assertTrue(obj, self.obj[0]['name'])
690 def test_list_using_meta(self):
691 meta = {'quality':'aaa'}
692 for o in self.obj[:2]:
693 self.client.update_object_metadata(self.container[0], o['name'],
695 meta = {'stock':'true'}
696 for o in self.obj[3:5]:
697 self.client.update_object_metadata(self.container[0], o['name'],
700 obj = self.client.list_objects(self.container[0], meta='Quality')
701 self.assertEqual(len(obj), 2)
702 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
704 # test case insensitive
705 obj = self.client.list_objects(self.container[0], meta='quality')
706 self.assertEqual(len(obj), 2)
707 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
709 # test multiple matches
710 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
711 self.assertEqual(len(obj), 4)
712 self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
714 # test non 1-1 multiple match
715 obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
716 self.assertEqual(len(obj), 2)
717 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
719 def test_if_modified_since(self):
720 t = datetime.datetime.utcnow()
721 t2 = t - datetime.timedelta(minutes=10)
724 self.upload_random_data(self.container[0], o_names[0])
726 for f in DATE_FORMATS:
727 past = t2.strftime(f)
729 o = self.client.list_objects(self.container[0],
730 if_modified_since=past)
732 self.client.list_objects(self.container[0]))
734 self.failIf(f.status == 304) #fail if not modified
736 def test_if_modified_since_invalid_date(self):
737 headers = {'if-modified-since':''}
738 o = self.client.list_objects(self.container[0], if_modified_since='')
739 self.assertEqual(o, self.client.list_objects(self.container[0]))
741 def test_if_not_modified_since(self):
742 now = datetime.datetime.utcnow()
743 since = now + datetime.timedelta(1)
745 for f in DATE_FORMATS:
746 args = {'if_modified_since':'%s' %since.strftime(f)}
749 self.assert_raises_fault(304, self.client.list_objects,
750 self.container[0], **args)
752 def test_if_unmodified_since(self):
753 now = datetime.datetime.utcnow()
754 since = now + datetime.timedelta(1)
756 for f in DATE_FORMATS:
757 obj = self.client.list_objects(self.container[0],
758 if_unmodified_since=since.strftime(f))
761 self.assertEqual(obj, self.client.list_objects(self.container[0]))
763 def test_if_unmodified_since_precondition_failed(self):
764 t = datetime.datetime.utcnow()
765 t2 = t - datetime.timedelta(minutes=10)
768 self.client.create_container('dummy')
770 for f in DATE_FORMATS:
771 past = t2.strftime(f)
773 args = {'if_unmodified_since':'%s' %past}
775 #assert precondition failed
776 self.assert_raises_fault(412, self.client.list_objects,
777 self.container[0], **args)
779 class ContainerPut(BaseTestCase):
781 BaseTestCase.setUp(self)
782 self.containers = ['c1', 'c2']
784 def test_create(self):
785 self.client.create_container(self.containers[0])
786 containers = self.client.list_containers()
787 self.assertTrue(self.containers[0] in containers)
788 self.assert_container_exists(self.containers[0])
790 def test_create_twice(self):
791 self.client.create_container(self.containers[0])
792 self.assertTrue(not self.client.create_container(self.containers[0]))
794 def test_quota(self):
795 self.client.create_container(self.containers[0])
797 policy = {'quota':100}
798 self.client.set_container_policies('c1', **policy)
800 meta = self.client.retrieve_container_metadata('c1')
801 self.assertTrue('x-container-policy-quota' in meta)
802 self.assertEqual(meta['x-container-policy-quota'], '100')
805 kwargs = {'length':101}
806 self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
810 self.client.set_container_policies('c1', **policy)
812 class ContainerPost(BaseTestCase):
814 BaseTestCase.setUp(self)
815 self.container = 'apples'
816 self.client.create_container(self.container)
818 def test_update_meta(self):
819 meta = {'test':'test33',
821 self.client.update_container_metadata(self.container, **meta)
822 headers = self.client.retrieve_container_metadata(self.container)
823 for k,v in meta.items():
824 k = 'x-container-meta-%s' % k
825 self.assertTrue(headers[k])
826 self.assertEqual(headers[k], v)
828 class ContainerDelete(BaseTestCase):
830 BaseTestCase.setUp(self)
831 self.containers = ['c1', 'c2']
832 for c in self.containers:
833 self.client.create_container(c)
835 def test_delete(self):
836 status = self.client.delete_container(self.containers[0])[0]
837 self.assertEqual(status, 204)
839 def test_delete_non_empty(self):
840 self.upload_random_data(self.containers[1], o_names[0])
841 self.assert_raises_fault(409, self.client.delete_container,
844 def test_delete_invalid(self):
845 self.assert_raises_fault(404, self.client.delete_container, 'c3')
847 def test_delete_contents(self):
848 self.client.create_folder(self.containers[0], 'folder-1')
849 self.upload_random_data(self.containers[1], 'folder-1/%s' % o_names[0])
850 self.client.create_folder(self.containers[0], 'folder-1/subfolder')
851 self.client.create_folder(self.containers[0], 'folder-2/%s' % o_names[1])
853 objects = self.client.list_objects(self.containers[0])
854 self.client.delete_container(self.containers[0], delimiter='/')
856 self.assert_object_not_exists(self.containers[0], o)
857 self.assert_container_exists(self.containers[0])
859 class ObjectGet(BaseTestCase):
861 BaseTestCase.setUp(self)
862 self.containers = ['c1', 'c2']
863 #create some containers
864 for c in self.containers:
865 self.client.create_container(c)
868 names = ('obj1', 'obj2')
871 self.objects.append(self.upload_random_data(self.containers[1], n))
873 def test_versions(self):
874 c = self.containers[1]
876 b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
877 self.assert_versionlist_structure(b)
880 meta = {'quality':'AAA', 'stock':True}
881 self.client.update_object_metadata(c, o['name'], **meta)
883 a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
884 self.assert_versionlist_structure(a)
885 self.assertEqual(len(b)+1, len(a))
886 self.assertEqual(b, a[:-1])
888 #get exact previous version metadata
890 v_meta = self.client.retrieve_object_metadata(c, o['name'],
893 for k in meta.keys():
894 self.assertTrue(k not in v_meta)
897 data = get_random_data()
898 self.client.update_object(c, o['name'], StringIO(data))
900 aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
901 self.assert_versionlist_structure(aa)
902 self.assertEqual(len(a)+1, len(aa))
903 self.assertEqual(a, aa[:-1])
905 #get exact previous version
907 v_data = self.client.retrieve_object_version(c, o['name'], version=v)
908 self.assertEqual(o['data'], v_data)
909 self.assertEqual(self.client.retrieve_object(c, o['name']),
910 '%s%s' %(v_data, data))
914 o = self.client.retrieve_object(self.containers[1],
915 self.objects[0]['name'],
916 self.objects[0]['meta'])
917 self.assertEqual(o, self.objects[0]['data'])
919 def test_objects_with_trailing_spaces(self):
920 self.client.create_container('test')
922 self.upload_random_data('test', 'a')
923 #look for 'a ' object
924 self.assert_raises_fault(404, self.client.retrieve_object,
928 self.client.delete_object('test', 'a')
929 self.assert_raises_fault(404, self.client.retrieve_object,
933 self.upload_random_data('test', 'a ')
935 self.assert_raises_fault(404, self.client.retrieve_object,
938 def test_get_invalid(self):
939 self.assert_raises_fault(404, self.client.retrieve_object,
940 self.containers[0], self.objects[0]['name'])
942 def test_get_partial(self):
943 #perform get with range
944 status, headers, data = self.client.request_object(self.containers[1],
945 self.objects[0]['name'],
948 #assert successful partial content
949 self.assertEqual(status, 206)
952 self.assertEqual(headers['content-type'],
953 self.objects[0]['meta']['content_type'])
955 #assert content length
956 self.assertEqual(int(headers['content-length']), 500)
959 self.assertEqual(self.objects[0]['data'][:500], data)
961 def test_get_final_500(self):
962 #perform get with range
963 headers = {'range':'bytes=-500'}
964 status, headers, data = self.client.request_object(self.containers[1],
965 self.objects[0]['name'],
968 #assert successful partial content
969 self.assertEqual(status, 206)
972 self.assertEqual(headers['content-type'],
973 self.objects[0]['meta']['content_type'])
975 #assert content length
976 self.assertEqual(int(headers['content-length']), 500)
979 self.assertTrue(self.objects[0]['data'][-500:], data)
981 def test_get_rest(self):
982 #perform get with range
983 offset = len(self.objects[0]['data']) - 500
984 status, headers, data = self.client.request_object(self.containers[1],
985 self.objects[0]['name'],
986 range='bytes=%s-' %offset)
988 #assert successful partial content
989 self.assertEqual(status, 206)
992 self.assertEqual(headers['content-type'],
993 self.objects[0]['meta']['content_type'])
995 #assert content length
996 self.assertEqual(int(headers['content-length']), 500)
999 self.assertTrue(self.objects[0]['data'][-500:], data)
1001 def test_get_range_not_satisfiable(self):
1002 #perform get with range
1003 offset = len(self.objects[0]['data']) + 1
1005 #assert range not satisfiable
1006 self.assert_raises_fault(416, self.client.retrieve_object,
1007 self.containers[1], self.objects[0]['name'],
1008 range='bytes=0-%s' %offset)
1010 def test_multiple_range(self):
1011 #perform get with multiple range
1012 ranges = ['0-499', '-500', '1000-']
1013 bytes = 'bytes=%s' % ','.join(ranges)
1014 status, headers, data = self.client.request_object(self.containers[1],
1015 self.objects[0]['name'],
1018 # assert partial content
1019 self.assertEqual(status, 206)
1021 # assert Content-Type of the reply will be multipart/byteranges
1022 self.assertTrue(headers['content-type'])
1023 content_type_parts = headers['content-type'].split()
1024 self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
1026 boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
1027 cparts = data.split(boundary)[1:-1]
1029 # assert content parts are exactly 2
1030 self.assertEqual(len(cparts), len(ranges))
1032 # for each content part assert headers
1034 for cpart in cparts:
1035 content = cpart.split('\r\n')
1036 headers = content[1:3]
1037 content_range = headers[0].split(': ')
1038 self.assertEqual(content_range[0], 'Content-Range')
1040 r = ranges[i].split('-')
1041 if not r[0] and not r[1]:
1044 start = len(self.objects[0]['data']) - int(r[1])
1045 end = len(self.objects[0]['data'])
1048 end = len(self.objects[0]['data'])
1052 fdata = self.objects[0]['data'][start:end]
1053 sdata = '\r\n'.join(content[4:-1])
1054 self.assertEqual(len(fdata), len(sdata))
1055 self.assertEquals(fdata, sdata)
1058 def test_multiple_range_not_satisfiable(self):
1059 #perform get with multiple range
1060 out_of_range = len(self.objects[0]['data']) + 1
1061 ranges = ['0-499', '-500', '%d-' %out_of_range]
1062 bytes = 'bytes=%s' % ','.join(ranges)
1064 # assert partial content
1065 self.assert_raises_fault(416, self.client.retrieve_object,
1067 self.objects[0]['name'], range=bytes)
1069 def test_get_with_if_match(self):
1070 #perform get with If-Match
1071 etag = self.objects[0]['hash']
1072 status, headers, data = self.client.request_object(self.containers[1],
1073 self.objects[0]['name'],
1076 self.assertEqual(status, 200)
1078 #assert content-type
1079 self.assertEqual(headers['content-type'],
1080 self.objects[0]['meta']['content_type'])
1082 #assert response content
1083 self.assertEqual(self.objects[0]['data'], data)
1085 def test_get_with_if_match_star(self):
1086 #perform get with If-Match *
1087 headers = {'if-match':'*'}
1088 status, headers, data = self.client.request_object(self.containers[1],
1089 self.objects[0]['name'],
1092 self.assertEqual(status, 200)
1094 #assert content-type
1095 self.assertEqual(headers['content-type'],
1096 self.objects[0]['meta']['content_type'])
1098 #assert response content
1099 self.assertEqual(self.objects[0]['data'], data)
1101 def test_get_with_multiple_if_match(self):
1102 #perform get with If-Match
1103 etags = [i['hash'] for i in self.objects if i]
1104 etags = ','.join('"%s"' % etag for etag in etags)
1105 status, headers, data = self.client.request_object(self.containers[1],
1106 self.objects[0]['name'],
1109 self.assertEqual(status, 200)
1111 #assert content-type
1112 self.assertEqual(headers['content-type'],
1113 self.objects[0]['meta']['content_type'])
1115 #assert content-type
1116 self.assertEqual(headers['content-type'],
1117 self.objects[0]['meta']['content_type'])
1119 #assert response content
1120 self.assertEqual(self.objects[0]['data'], data)
1122 def test_if_match_precondition_failed(self):
1123 #assert precondition failed
1124 self.assert_raises_fault(412, self.client.retrieve_object,
1126 self.objects[0]['name'], if_match='123')
1128 def test_if_none_match(self):
1129 #perform get with If-None-Match
1130 status, headers, data = self.client.request_object(self.containers[1],
1131 self.objects[0]['name'],
1132 if_none_match='123')
1135 self.assertEqual(status, 200)
1137 #assert content-type
1138 self.assertEqual(headers['content_type'],
1139 self.objects[0]['meta']['content_type'])
1141 def test_if_none_match(self):
1142 #perform get with If-None-Match * and assert not modified
1143 self.assert_raises_fault(304, self.client.retrieve_object,
1145 self.objects[0]['name'],
1148 def test_if_none_match_not_modified(self):
1149 #perform get with If-None-Match and assert not modified
1150 self.assert_raises_fault(304, self.client.retrieve_object,
1152 self.objects[0]['name'],
1153 if_none_match=self.objects[0]['hash'])
1155 meta = self.client.retrieve_object_metadata(self.containers[1],
1156 self.objects[0]['name'])
1157 self.assertEqual(meta['etag'], self.objects[0]['hash'])
1159 def test_if_modified_since(self):
1160 t = datetime.datetime.utcnow()
1161 t2 = t - datetime.timedelta(minutes=10)
1164 self.upload_data(self.containers[1],
1165 self.objects[0]['name'],
1166 self.objects[0]['data'][:200])
1168 for f in DATE_FORMATS:
1169 past = t2.strftime(f)
1171 headers = {'if-modified-since':'%s' %past}
1173 o = self.client.retrieve_object(self.containers[1],
1174 self.objects[0]['name'],
1175 if_modified_since=past)
1177 self.client.retrieve_object(self.containers[1],
1178 self.objects[0]['name']))
1180 self.failIf(f.status == 304)
1182 def test_if_modified_since_invalid_date(self):
1183 o = self.client.retrieve_object(self.containers[1],
1184 self.objects[0]['name'],
1185 if_modified_since='')
1186 self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1187 self.objects[0]['name']))
1189 def test_if_not_modified_since(self):
1190 now = datetime.datetime.utcnow()
1191 since = now + datetime.timedelta(1)
1193 for f in DATE_FORMATS:
1194 #assert not modified
1195 self.assert_raises_fault(304, self.client.retrieve_object,
1196 self.containers[1], self.objects[0]['name'],
1197 if_modified_since=since.strftime(f))
1199 def test_if_unmodified_since(self):
1200 now = datetime.datetime.utcnow()
1201 since = now + datetime.timedelta(1)
1203 for f in DATE_FORMATS:
1204 t = since.strftime(f)
1205 status, headers, data = self.client.request_object(self.containers[1],
1206 self.objects[0]['name'],
1207 if_unmodified_since=t)
1209 self.assertEqual(status, 200)
1210 self.assertEqual(self.objects[0]['data'], data)
1212 #assert content-type
1213 self.assertEqual(headers['content-type'],
1214 self.objects[0]['meta']['content_type'])
1216 def test_if_unmodified_since_precondition_failed(self):
1217 t = datetime.datetime.utcnow()
1218 t2 = t - datetime.timedelta(minutes=10)
1221 self.upload_data(self.containers[1],
1222 self.objects[0]['name'],
1223 self.objects[0]['data'][:200])
1225 for f in DATE_FORMATS:
1226 past = t2.strftime(f)
1227 #assert precondition failed
1228 self.assert_raises_fault(412, self.client.retrieve_object,
1229 self.containers[1], self.objects[0]['name'],
1230 if_unmodified_since=past)
1232 def test_hashes(self):
1235 o = self.upload_random_data(self.containers[1], fname, l)
1237 body = self.client.retrieve_object(self.containers[1], fname,
1239 hashes = body['hashes']
1240 block_size = body['block_size']
1241 block_hash = body['block_hash']
1242 block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1243 self.assertTrue(len(hashes), block_num)
1246 start = i * block_size
1247 end = (i + 1) * block_size
1248 hash = compute_block_hash(o['data'][start:end], block_hash)
1249 self.assertEqual(h, hash)
1252 class ObjectPut(BaseTestCase):
1254 BaseTestCase.setUp(self)
1255 self.container = 'c1'
1256 self.client.create_container(self.container)
1258 def test_upload(self):
1260 meta = {'test':'test1'}
1261 o = self.upload_random_data(self.container, name, **meta)
1263 headers = self.client.retrieve_object_metadata(self.container,
1266 self.assertTrue('test' in headers.keys())
1267 self.assertEqual(headers['test'], meta['test'])
1269 #assert uploaded content
1270 status, h, data = self.client.request_object(self.container, name)
1271 self.assertEqual(len(o['data']), int(h['content-length']))
1272 self.assertEqual(o['data'], data)
1274 #assert content-type
1275 self.assertEqual(h['content-type'], o['meta']['content_type'])
1277 def _test_maximum_upload_size_exceeds(self):
1279 meta = {'test':'test1'}
1281 length= 5 * (1024 * 1024 * 1024) + 1
1282 self.assert_raises_fault(400, self.upload_random_data, self.container,
1283 name, length, **meta)
1285 def test_upload_with_name_containing_slash(self):
1286 name = '/%s' % o_names[0]
1287 meta = {'test':'test1'}
1288 o = self.upload_random_data(self.container, name, **meta)
1290 self.assertEqual(o['data'],
1291 self.client.retrieve_object(self.container, name))
1293 self.assertTrue(name in self.client.list_objects(self.container))
1295 def test_create_directory_marker(self):
1296 self.client.create_directory_marker(self.container, 'foo')
1297 meta = self.client.retrieve_object_metadata(self.container, 'foo')
1298 self.assertEqual(meta['content-length'], '0')
1299 self.assertEqual(meta['content-type'], 'application/directory')
1301 def test_upload_unprocessable_entity(self):
1302 meta={'etag':'123', 'test':'test1'}
1304 #assert unprocessable entity
1305 self.assert_raises_fault(422, self.upload_random_data, self.container,
1308 def test_chunked_transfer(self):
1309 data = get_random_data()
1311 self.client.create_object_using_chunks(self.container, objname,
1314 uploaded_data = self.client.retrieve_object(self.container, objname)
1315 self.assertEqual(data, uploaded_data)
1317 def test_manifestation(self):
1318 prefix = 'myobject/'
1321 part = '%s%d' %(prefix, i)
1322 o = self.upload_random_data(self.container, part)
1325 manifest = '%s/%s' %(self.container, prefix)
1326 self.client.create_manifestation(self.container, 'large-object', manifest)
1328 self.assert_object_exists(self.container, 'large-object')
1329 self.assertEqual(data, self.client.retrieve_object(self.container,
1332 r = self.client.retrieve_object_hashmap(self.container,'large-object')
1333 hashes = r['hashes']
1334 block_size = int(r['block_size'])
1335 block_hash = r['block_hash']
1337 block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1338 self.assertEqual(block_num, len(hashes))
1340 #wrong manifestation
1341 self.client.create_manifestation(self.container, 'large-object',
1342 '%s/invalid' % self.container)
1343 self.assertEqual('', self.client.retrieve_object(self.container,
1346 def test_create_zero_length_object(self):
1349 zero = self.client.create_zero_length_object(c, o)
1350 zero_meta = self.client.retrieve_object_metadata(c, o)
1351 zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1352 zero_data = self.client.retrieve_object(c, o)
1354 self.assertEqual(int(zero_meta['content-length']), 0)
1355 hasher = newhasher('sha256')
1357 emptyhash = hasher.digest()
1358 self.assertEqual(zero_hash, [hexlify(emptyhash)])
1359 self.assertEqual(zero_data, '')
1361 def test_create_object_by_hashmap(self):
1364 self.upload_random_data(c, o)
1365 hashmap = self.client.retrieve_object(c, o, format='json')
1367 self.client.create_object_by_hashmap(c, o2, hashmap)
1368 self.assertEqual(self.client.retrieve_object(c, o),
1369 self.client.retrieve_object(c, o))
1371 class ObjectCopy(BaseTestCase):
1373 BaseTestCase.setUp(self)
1374 self.containers = ['c1', 'c2']
1375 for c in self.containers:
1376 self.client.create_container(c)
1377 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1379 def test_copy(self):
1380 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1381 self.containers[0], self.obj['name']):
1383 meta = {'test':'testcopy'}
1384 status = self.client.copy_object(self.containers[0],
1390 #assert copy success
1391 self.assertEqual(status, 201)
1393 #assert access the new object
1394 headers = self.client.retrieve_object_metadata(self.containers[0],
1396 self.assertTrue('x-object-meta-test' in headers.keys())
1397 self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1399 #assert etag is the same
1400 self.assertEqual(headers['etag'], self.obj['hash'])
1402 #assert src object still exists
1403 self.assert_object_exists(self.containers[0], self.obj['name'])
1405 def test_copy_from_different_container(self):
1406 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1407 self.containers[0], self.obj['name']):
1408 meta = {'test':'testcopy'}
1409 status = self.client.copy_object(self.containers[0],
1414 self.assertEqual(status, 201)
1416 # assert updated metadata
1417 meta = self.client.retrieve_object_metadata(self.containers[1],
1420 self.assertTrue('test' in meta.keys())
1421 self.assertTrue(meta['test'], 'testcopy')
1423 #assert src object still exists
1424 self.assert_object_exists(self.containers[0], self.obj['name'])
1426 def test_copy_invalid(self):
1427 #copy from invalid object
1428 meta = {'test':'testcopy'}
1429 self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1430 'test.py', self.containers[1], 'testcopy', meta)
1432 #copy from invalid container
1433 meta = {'test':'testcopy'}
1434 self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1435 self.obj['name'], self.containers[1],
1438 def test_copy_dir(self):
1439 self.client.create_folder(self.containers[0], 'dir')
1440 self.client.create_folder(self.containers[0], 'dir/subdir')
1441 self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1442 self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1443 self.client.create_folder(self.containers[0], 'dirs')
1445 objects = self.client.list_objects(self.containers[0], prefix='dir')
1446 self.client.copy_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/')
1447 for object in objects[:-1]:
1448 self.assert_object_exists(self.containers[0], object)
1449 self.assert_object_exists(self.containers[1], object.replace('dir', 'dir-backup', 1))
1450 meta0 = self.client.retrieve_object_metadata(self.containers[0], object)
1451 meta1 = self.client.retrieve_object_metadata(self.containers[1], object.replace('dir', 'dir-backup', 1))
1452 t = ('content-length', 'x-object-hash', 'content-type')
1453 (self.assertEqual(meta0[elem], meta1[elem]) for elem in t)
1454 self.assert_object_not_exists(self.containers[1], objects[-1])
1456 class ObjectMove(BaseTestCase):
1458 BaseTestCase.setUp(self)
1459 self.containers = ['c1', 'c2']
1460 for c in self.containers:
1461 self.client.create_container(c)
1462 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1464 def test_move(self):
1465 meta = self.client.retrieve_object_metadata(self.containers[0],
1467 self.assertTrue('x-object-uuid' in meta)
1468 uuid = meta['x-object-uuid']
1471 meta = {'test':'testcopy'}
1472 src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1473 status = self.client.move_object(self.containers[0], self.obj['name'],
1474 self.containers[0], 'testcopy',
1477 #assert successful move
1478 self.assertEqual(status, 201)
1480 #assert updated metadata
1481 meta = self.client.retrieve_object_metadata(self.containers[0],
1483 self.assertTrue('x-object-meta-test' in meta.keys())
1484 self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1487 self.assertTrue(meta['x-object-uuid'], uuid)
1489 #assert src object no more exists
1490 self.assert_object_not_exists(self.containers[0], self.obj['name'])
1493 def test_move_dir(self):
1495 self.client.create_folder(self.containers[0], 'dir')
1496 meta['dir'] = self.client.retrieve_object_metadata(self.containers[0], 'dir')
1497 self.client.create_folder(self.containers[0], 'dir/subdir')
1498 meta['dir/subdir'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/subdir')
1499 self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1500 meta['dir/object1.jpg'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/object1.jpg')
1501 self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1502 meta['dir/subdir/object2.pdf'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/subdir/object2.pdf')
1503 self.client.create_folder(self.containers[0], 'dirs')
1504 meta['dirs'] = self.client.retrieve_object_metadata(self.containers[0], 'dirs')
1506 objects = self.client.list_objects(self.containers[0], prefix='dir')
1507 self.client.move_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/')
1508 for object in objects[:-1]:
1509 self.assert_object_not_exists(self.containers[0], object)
1510 self.assert_object_exists(self.containers[1], object.replace('dir', 'dir-backup', 1))
1511 meta1 = self.client.retrieve_object_metadata(self.containers[1], object.replace('dir', 'dir-backup', 1))
1512 t = ('content-length', 'x-object-hash', 'content-type')
1513 (self.assertEqual(meta0[elem], meta1[elem]) for elem in t)
1514 self.assert_object_exists(self.containers[0], objects[-1])
1515 self.assert_object_not_exists(self.containers[1], objects[-1])
1517 class ObjectPost(BaseTestCase):
1519 BaseTestCase.setUp(self)
1520 self.containers = ['c1', 'c2']
1521 for c in self.containers:
1522 self.client.create_container(c)
1525 self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1527 def test_update_meta(self):
1528 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1530 self.obj[0]['name']):
1531 #perform update metadata
1532 more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1533 status = self.client.update_object_metadata(self.containers[0],
1534 self.obj[0]['name'],
1536 #assert request accepted
1537 self.assertEqual(status, 202)
1539 #assert old metadata are still there
1540 headers = self.client.retrieve_object_metadata(self.containers[0],
1541 self.obj[0]['name'],
1543 #assert new metadata have been updated
1544 for k,v in more.items():
1545 self.assertTrue(k in headers.keys())
1546 self.assertTrue(headers[k], v)
1549 more = {'f' * 114: 'b' * 257}
1550 self.assert_raises_fault(400, self.client.update_object_metadata,
1552 self.obj[0]['name'],
1555 #perform update metadata
1556 more = {'α': 'β' * 256}
1557 status = self.client.update_object_metadata(self.containers[0],
1558 self.obj[0]['name'],
1560 #assert request accepted
1561 self.assertEqual(status, 202)
1563 #assert old metadata are still there
1564 headers = self.client.retrieve_object_metadata(self.containers[0],
1565 self.obj[0]['name'],
1567 #assert new metadata have been updated
1568 for k,v in more.items():
1569 self.assertTrue(k in headers.keys())
1570 self.assertTrue(headers[k], v)
1573 more = {'α': 'β' * 257}
1574 self.assert_raises_fault(400, self.client.update_object_metadata,
1576 self.obj[0]['name'],
1579 def test_update_object(self,
1582 instance_length = True,
1583 content_length = 500):
1584 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1586 self.obj[0]['name']):
1587 l = len(self.obj[0]['data'])
1588 range = 'bytes %d-%d/%s' %(first_byte_pos,
1590 l if instance_length else '*')
1591 partial = last_byte_pos - first_byte_pos + 1
1592 length = first_byte_pos + partial
1593 data = get_random_data(partial)
1594 args = {'content_type':'application/octet-stream',
1595 'content_range':'%s' %range}
1597 args['content_length'] = content_length
1599 r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1600 StringIO(data), **args)
1603 if partial < 0 or (instance_length and l <= last_byte_pos):
1604 self.assertEqual(status, 202)
1606 self.assertEqual(status, 204)
1607 #check modified object
1608 content = self.client.retrieve_object(self.containers[0],
1609 self.obj[0]['name'])
1610 self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1611 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1612 self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1613 self.assertEqual(etag, compute_md5_hash(content))
1615 def test_update_object_lt_blocksize(self):
1616 self.test_update_object(10, 20, content_length=None)
1618 def test_update_object_gt_blocksize(self):
1619 o = self.upload_random_data(self.containers[0], o_names[1],
1620 length=4*1024*1024+5)
1621 c = self.containers[0]
1624 first_byte_pos = 4*1024*1024+1
1625 last_byte_pos = 4*1024*1024+4
1626 l = last_byte_pos - first_byte_pos + 1
1627 data = get_random_data(l)
1628 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1629 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1630 content = self.client.retrieve_object(c, o_name)
1631 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1632 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1633 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1635 def test_update_object_divided_by_blocksize(self):
1636 o = self.upload_random_data(self.containers[0], o_names[1],
1637 length=4*1024*1024+5)
1638 c = self.containers[0]
1641 first_byte_pos = 4*1024*1024
1642 last_byte_pos = 5*1024*1024
1643 l = last_byte_pos - first_byte_pos + 1
1644 data = get_random_data(l)
1645 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1646 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1647 content = self.client.retrieve_object(c, o_name)
1648 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1649 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1650 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1652 def test_update_object_no_content_length(self):
1653 self.test_update_object(content_length = None)
1655 def test_update_object_invalid_content_length(self):
1656 with AssertContentInvariant(self.client.retrieve_object,
1657 self.containers[0], self.obj[0]['name']):
1658 self.assert_raises_fault(400, self.test_update_object,
1659 content_length = 1000)
1661 def test_update_object_invalid_range(self):
1662 with AssertContentInvariant(self.client.retrieve_object,
1663 self.containers[0], self.obj[0]['name']):
1664 self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1666 def test_update_object_invalid_range_and_length(self):
1667 with AssertContentInvariant(self.client.retrieve_object,
1668 self.containers[0], self.obj[0]['name']):
1669 self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1672 def test_update_object_invalid_range_with_no_content_length(self):
1673 with AssertContentInvariant(self.client.retrieve_object,
1674 self.containers[0], self.obj[0]['name']):
1675 self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1676 content_length = None)
1678 def test_update_object_out_of_limits(self):
1679 with AssertContentInvariant(self.client.retrieve_object,
1680 self.containers[0], self.obj[0]['name']):
1681 l = len(self.obj[0]['data'])
1682 self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1684 def test_append(self):
1685 data = get_random_data(500)
1687 self.client.update_object(self.containers[0], self.obj[0]['name'],
1688 StringIO(data), content_length=500,
1689 content_type='application/octet-stream')
1691 content = self.client.retrieve_object(self.containers[0],
1692 self.obj[0]['name'])
1693 self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1694 self.assertEqual(content[:-500], self.obj[0]['data'])
1696 def test_update_with_chunked_transfer(self):
1697 data = get_random_data(500)
1699 fl = len(self.obj[0]['data'])
1701 self.client.update_object_using_chunks(self.containers[0],
1702 self.obj[0]['name'],
1705 content_type='application/octet-stream')
1707 #check modified object
1708 content = self.client.retrieve_object(self.containers[0],
1709 self.obj[0]['name'])
1710 self.assertEqual(content[0:dl], data)
1711 self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1713 def test_update_from_other_object(self):
1714 c = self.containers[0]
1718 source_data = self.client.retrieve_object(c, src)
1719 source_meta = self.client.retrieve_object_metadata(c, src)
1720 source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1722 #update zero length object
1723 self.client.create_zero_length_object(c, dest)
1724 source_object = '/%s/%s' % (c, src)
1725 self.client.update_from_other_source(c, dest, source_object)
1726 dest_data = self.client.retrieve_object(c, src)
1727 dest_meta = self.client.retrieve_object_metadata(c, dest)
1728 dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1729 self.assertEqual(source_data, dest_data)
1730 self.assertEqual(source_hash, dest_hash)
1733 self.client.update_from_other_source(c, dest, source_object)
1734 content = self.client.retrieve_object(c, dest)
1735 self.assertEqual(source_data * 2, content)
1737 def test_update_range_from_other_object(self):
1738 c = self.containers[0]
1742 src = self.obj[1]['name']
1743 src_data = self.client.retrieve_object(c, src)
1745 #update zero length object
1746 prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1747 source_object = '/%s/%s' % (c, src)
1748 first_byte_pos = 4*1024*1024+1
1749 last_byte_pos = 4*1024*1024+4
1750 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1751 self.client.update_from_other_source(c, dest, source_object,
1752 content_range=range)
1753 content = self.client.retrieve_object(c, dest)
1754 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1755 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1756 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1758 def test_update_hashes_from_other_object(self):
1759 c = self.containers[0]
1763 src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1765 #update zero length object
1766 prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1767 source_object = '/%s/%s' % (c, o_names[0])
1768 first_byte_pos = 4*1024*1024
1769 last_byte_pos = 5*1024*1024
1770 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1771 self.client.update_from_other_source(c, dest, source_object,
1772 content_range=range)
1773 content = self.client.retrieve_object(c, dest)
1774 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1775 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1776 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1779 def test_update_zero_length_object(self):
1780 c = self.containers[0]
1783 zero = self.client.create_zero_length_object(c, o)
1785 data = get_random_data()
1786 self.client.update_object(c, o, StringIO(data))
1787 self.client.create_object(c, other, StringIO(data))
1789 self.assertEqual(self.client.retrieve_object(c, o),
1790 self.client.retrieve_object(c, other))
1792 self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1793 self.client.retrieve_object_hashmap(c, other)["hashes"])
1795 class ObjectDelete(BaseTestCase):
1797 BaseTestCase.setUp(self)
1798 self.containers = ['c1', 'c2']
1799 for c in self.containers:
1800 self.client.create_container(c)
1801 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1803 def test_delete(self):
1804 #perform delete object
1805 self.client.delete_object(self.containers[0], self.obj['name'])[0]
1807 def test_delete_invalid(self):
1808 #assert item not found
1809 self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1812 def test_delete_dir(self):
1813 self.client.create_folder(self.containers[0], 'dir')
1814 self.client.create_folder(self.containers[0], 'dir/subdir')
1815 self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1816 self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1817 self.client.create_folder(self.containers[0], 'dirs')
1819 objects = self.client.list_objects(self.containers[0], prefix='dir')
1820 self.client.delete_object(self.containers[0], 'dir', delimiter='/')
1821 for object in objects[:-1]:
1822 self.assert_object_not_exists(self.containers[0], object)
1823 self.assert_object_exists(self.containers[0], objects[-1])
1825 class ListSharing(BaseTestCase):
1827 BaseTestCase.setUp(self)
1829 self.client.create_container('c%s' %i)
1830 self.client.create_container('c')
1832 self.upload_random_data('c1', 'o%s' %i)
1833 accounts = OTHER_ACCOUNTS.copy()
1834 self.o1_sharing_with = accounts.popitem()
1835 self.o1_sharing = [self.o1_sharing_with[1]]
1836 self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1840 l.append(accounts.popitem())
1842 def test_list_other_shared(self):
1843 self.other = Pithos_Client(get_url(),
1844 self.o1_sharing_with[0],
1845 self.o1_sharing_with[1])
1846 self.assertTrue(get_user() in self.other.list_shared_by_others())
1848 def test_list_my_shared(self):
1849 my_shared_containers = self.client.list_containers(shared=True)
1850 self.assertTrue('c1' in my_shared_containers)
1851 self.assertTrue('c2' not in my_shared_containers)
1853 my_shared_objects = self.client.list_objects('c1', shared=True)
1854 self.assertTrue('o1' in my_shared_objects)
1855 self.assertTrue('o2' not in my_shared_objects)
1857 class List(BaseTestCase):
1859 BaseTestCase.setUp(self)
1860 for i in range(1, 5):
1862 self.client.create_container(c)
1863 for j in range(1, 3):
1865 self.upload_random_data(c, o)
1867 self.client.share_object(c, 'o1', ['papagian'], read=True)
1869 self.client.publish_object(c, 'o2')
1871 def test_shared_public(self):
1872 func, kwargs = self.client.list_containers, {'shared':True}
1874 self.assertEqual(l, ['c1', 'c2'])
1875 self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1877 func, kwargs = self.client.list_containers, {'public':True}
1879 self.assertEqual(l, ['c1', 'c3'])
1880 self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1882 func, kwargs = self.client.list_containers, {'shared':True, 'public':True}
1884 self.assertEqual(l, ['c1', 'c2', 'c3'])
1885 self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1888 func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True}
1889 l = func(*args, **kwargs)
1890 self.assertEqual(l, ['o1'])
1891 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1893 func, args, kwargs = self.client.list_objects, ['c1'], {'public':True}
1894 l = func(*args, **kwargs)
1895 self.assertEqual(l, ['o2'])
1896 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1898 func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True, 'public':True}
1899 l = func(*args, **kwargs)
1900 self.assertEqual(l, ['o1', 'o2'])
1901 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1904 func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True}
1905 l = func(*args, **kwargs)
1906 self.assertEqual(l, ['o1'])
1907 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1909 func, args, kwargs = self.client.list_objects, ['c2'], {'public':True}
1910 l = func(*args, **kwargs)
1911 self.assertEqual(l, '')
1912 self.assertEqual([], func(*args, format='json', **kwargs))
1914 func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True, 'public':True}
1915 l = func(*args, **kwargs)
1916 self.assertEqual(l, ['o1'])
1917 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1920 func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True}
1921 l = func(*args, **kwargs)
1922 self.assertEqual(l, '')
1923 self.assertEqual([], func(*args, format='json', **kwargs))
1925 func, args, kwargs = self.client.list_objects, ['c3'], {'public':True}
1926 l = func(*args, **kwargs)
1927 self.assertEqual(l, ['o2'])
1928 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1930 func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True, 'public':True}
1931 l = func(*args, **kwargs)
1932 self.assertEqual(l, ['o2'])
1933 self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1936 func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True}
1937 l = func(*args, **kwargs)
1938 self.assertEqual(l, '')
1939 self.assertEqual([], func(*args, format='json', **kwargs))
1941 func, args, kwargs = self.client.list_objects, ['c4'], {'public':True}
1942 l = func(*args, **kwargs)
1943 self.assertEqual(l, '')
1944 self.assertEqual([], func(*args, format='json', **kwargs))
1946 func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True, 'public':True}
1947 l = func(*args, **kwargs)
1948 self.assertEqual(l, '')
1949 self.assertEqual([], func(*args, format='json', **kwargs))
1951 class TestGreek(BaseTestCase):
1952 def test_create_container(self):
1953 self.client.create_container('φάκελος')
1954 self.assert_container_exists('φάκελος')
1956 self.assertTrue('φάκελος' in self.client.list_containers())
1958 def test_create_object(self):
1959 self.client.create_container('φάκελος')
1960 self.upload_random_data('φάκελος', 'αντικείμενο')
1962 self.assert_object_exists('φάκελος', 'αντικείμενο')
1963 self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1965 def test_copy_object(self):
1966 src_container = 'φάκελος'
1967 src_object = 'αντικείμενο'
1968 dest_container = 'αντίγραφα'
1969 dest_object = 'ασφαλές-αντίγραφο'
1971 self.client.create_container(src_container)
1972 self.upload_random_data(src_container, src_object)
1974 self.client.create_container(dest_container)
1975 self.client.copy_object(src_container, src_object, dest_container,
1978 self.assert_object_exists(src_container, src_object)
1979 self.assert_object_exists(dest_container, dest_object)
1980 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1982 def test_move_object(self):
1983 src_container = 'φάκελος'
1984 src_object = 'αντικείμενο'
1985 dest_container = 'αντίγραφα'
1986 dest_object = 'ασφαλές-αντίγραφο'
1988 self.client.create_container(src_container)
1989 self.upload_random_data(src_container, src_object)
1991 self.client.create_container(dest_container)
1992 self.client.move_object(src_container, src_object, dest_container,
1995 self.assert_object_not_exists(src_container, src_object)
1996 self.assert_object_exists(dest_container, dest_object)
1997 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1999 def test_delete_object(self):
2000 self.client.create_container('φάκελος')
2001 self.upload_random_data('φάκελος', 'αντικείμενο')
2002 self.assert_object_exists('φάκελος', 'αντικείμενο')
2004 self.client.delete_object('φάκελος', 'αντικείμενο')
2005 self.assert_object_not_exists('φάκελος', 'αντικείμενο')
2006 self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
2008 def test_delete_container(self):
2009 self.client.create_container('φάκελος')
2010 self.assert_container_exists('φάκελος')
2012 self.client.delete_container('φάκελος')
2013 self.assert_container_not_exists('φάκελος')
2014 self.assertTrue('φάκελος' not in self.client.list_containers())
2016 def test_account_meta(self):
2017 meta = {'ποιότητα':'ΑΑΑ'}
2018 self.client.update_account_metadata(**meta)
2019 meta = self.client.retrieve_account_metadata(restricted=True)
2020 self.assertTrue('ποιότητα' in meta.keys())
2021 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2023 def test_container_meta(self):
2024 meta = {'ποιότητα':'ΑΑΑ'}
2025 self.client.create_container('φάκελος', meta=meta)
2027 meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
2028 self.assertTrue('ποιότητα' in meta.keys())
2029 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2031 def test_object_meta(self):
2032 self.client.create_container('φάκελος')
2033 meta = {'ποιότητα':'ΑΑΑ'}
2034 self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
2036 meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
2038 self.assertTrue('ποιότητα' in meta.keys())
2039 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2041 def test_list_meta_filtering(self):
2042 self.client.create_container('φάκελος')
2043 meta = {'ποιότητα':'ΑΑΑ'}
2044 self.upload_random_data('φάκελος', 'ο1', **meta)
2045 self.upload_random_data('φάκελος', 'ο2')
2046 self.upload_random_data('φάκελος', 'ο3')
2048 meta = {'ποσότητα':'μεγάλη'}
2049 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2050 objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
2051 self.assertEquals(objects, ['ο1', 'ο2'])
2053 objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
2054 self.assertEquals(objects, ['ο2', 'ο3'])
2056 objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
2057 self.assertEquals(objects, ['ο3'])
2059 meta = {'ποιότητα':'ΑΒ'}
2060 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2061 objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
2062 self.assertEquals(objects, ['ο1'])
2063 objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
2064 self.assertEquals(objects, ['ο2'])
2066 meta = {'έτος':'2011'}
2067 self.client.update_object_metadata('φάκελος', 'ο3', **meta)
2068 meta = {'έτος':'2012'}
2069 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2070 objects = self.client.list_objects('φάκελος', meta='έτος<2012')
2071 self.assertEquals(objects, ['ο3'])
2072 objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
2073 self.assertEquals(objects, ['ο2', 'ο3'])
2074 objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
2075 self.assertEquals(objects, '')
2077 def test_groups(self):
2079 groups = {'σεφς':'chazapis,διογένης'}
2080 self.client.set_account_groups(**groups)
2081 groups.update(self.initial_groups)
2082 self.assertEqual(groups['σεφς'],
2083 self.client.retrieve_account_groups()['σεφς'])
2086 self.client.create_container('φάκελος')
2087 o = self.upload_random_data('φάκελος', 'ο1')
2088 self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
2089 chef = Pithos_Client(get_url(),
2092 self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
2093 'φάκελος', 'ο1', account=get_user())
2096 self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
2097 new_data = get_random_data()
2098 self.assert_not_raises_fault(403, chef.update_object,
2099 'φάκελος', 'ο1', StringIO(new_data),
2102 server_data = self.client.retrieve_object('φάκελος', 'ο1')
2103 self.assertEqual(server_data[:len(o['data'])], o['data'])
2104 self.assertEqual(server_data[len(o['data']):], new_data)
2106 def test_manifestation(self):
2107 self.client.create_container('κουβάς')
2111 part = '%s%d' %(prefix, i)
2112 o = self.upload_random_data('κουβάς', part)
2115 self.client.create_container('φάκελος')
2116 manifest = '%s/%s' %('κουβάς', prefix)
2117 self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
2119 self.assert_object_exists('φάκελος', 'άπαντα')
2120 self.assertEqual(data, self.client.retrieve_object('φάκελος',
2123 #wrong manifestation
2124 self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
2125 self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
2127 def test_update_from_another_object(self):
2128 self.client.create_container('κουβάς')
2129 src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
2130 initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
2131 source_object = '/%s/%s' % ('κουβάς', 'πηγή')
2132 self.client.update_from_other_source('κουβάς', 'νέο', source_object)
2135 self.client.retrieve_object('κουβάς', 'νέο'),
2136 '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
2138 class TestPermissions(BaseTestCase):
2140 BaseTestCase.setUp(self)
2143 self.authorized = ['chazapis', 'verigak', 'gtsouk']
2144 groups = {'pithosdev':','.join(self.authorized)}
2145 self.client.set_account_groups(**groups)
2147 self.container = 'c'
2149 self.client.create_container(self.container)
2150 self.upload_random_data(self.container, self.object)
2151 self.upload_random_data(self.container, self.object+'/')
2152 self.upload_random_data(self.container, self.object+'/a')
2153 self.upload_random_data(self.container, self.object+'a')
2154 self.upload_random_data(self.container, self.object+'a/')
2155 self.dir_content_types = ('application/directory', 'application/folder')
2157 def assert_read(self, authorized=[], any=False, depth=0):
2158 for token, account in OTHER_ACCOUNTS.items():
2159 cl = Pithos_Client(get_url(), token, account)
2160 if account in authorized or any:
2161 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2162 self.container, self.object,
2165 self.assert_raises_fault(403, cl.retrieve_object_metadata,
2166 self.container, self.object,
2170 meta = self.client.retrieve_object_metadata(self.container, self.object)
2171 type = meta['content-type']
2172 derivatives = self.client.list_objects(self.container, prefix=self.object)
2173 #exclude the self.object
2174 del derivatives[derivatives.index(self.object)]
2175 for o in derivatives:
2176 for token, account in OTHER_ACCOUNTS.items():
2177 cl = Pithos_Client(get_url(), token, account)
2178 prefix = self.object if self.object.endswith('/') else self.object+'/'
2179 if (account in authorized or any) and \
2180 (type in self.dir_content_types) and \
2181 o.startswith(prefix):
2182 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2183 self.container, o, account=get_user())
2185 self.assert_raises_fault(403, cl.retrieve_object_metadata,
2186 self.container, o, account=get_user())
2188 def assert_write(self, authorized=[], any=False):
2189 o_data = self.client.retrieve_object(self.container, self.object)
2190 for token, account in OTHER_ACCOUNTS.items():
2191 cl = Pithos_Client(get_url(), token, account)
2192 new_data = get_random_data()
2193 if account in authorized or any:
2195 self.assert_not_raises_fault(403, cl.update_object,
2196 self.container, self.object, StringIO(new_data),
2200 server_data = cl.retrieve_object(self.container, self.object, account=get_user())
2201 self.assertEqual(o_data, server_data[:len(o_data)])
2202 self.assertEqual(new_data, server_data[len(o_data):])
2203 o_data = server_data
2205 self.failIf(f.status == 403)
2207 self.assert_raises_fault(403, cl.update_object,
2208 self.container, self.object, StringIO(new_data),
2211 meta = self.client.retrieve_object_metadata(self.container, self.object)
2212 type = meta['content-type']
2213 derivatives = self.client.list_objects(self.container, prefix=self.object)
2215 del derivatives[derivatives.index(self.object)]
2216 for o in derivatives:
2217 for token, account in OTHER_ACCOUNTS.items():
2218 prefix = self.object if self.object.endswith('/') else self.object+'/'
2219 cl = Pithos_Client(get_url(), token, account)
2220 new_data = get_random_data()
2221 if (account in authorized or any) and \
2222 (type in self.dir_content_types) and \
2223 o.startswith(prefix):
2225 self.assert_not_raises_fault(403, cl.update_object,
2230 server_data = cl.retrieve_object(self.container, o, account=get_user())
2231 self.assertEqual(new_data, server_data[-len(new_data):])
2233 self.failIf(f.status == 403)
2235 self.assert_raises_fault(403, cl.update_object,
2240 def test_group_read(self):
2241 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2242 self.assert_read(authorized=self.authorized)
2244 def test_read_many(self):
2245 self.client.share_object(self.container, self.object, self.authorized)
2246 self.assert_read(authorized=self.authorized)
2248 def test_read_by_everyone(self):
2249 self.client.share_object(self.container, self.object, ['*'])
2250 self.assert_read(any=True)
2252 def test_read_directory(self):
2253 for type in self.dir_content_types:
2254 #change content type
2255 self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2256 self.client.share_object(self.container, self.object, ['*'])
2257 self.assert_read(any=True)
2258 self.client.share_object(self.container, self.object, self.authorized)
2259 self.assert_read(authorized=self.authorized)
2260 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2261 self.assert_read(authorized=self.authorized)
2263 def test_group_write(self):
2264 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2265 self.assert_write(authorized=self.authorized)
2267 def test_write_many(self):
2268 self.client.share_object(self.container, self.object, self.authorized, read=False)
2269 self.assert_write(authorized=self.authorized)
2271 def test_write_by_everyone(self):
2272 self.client.share_object(self.container, self.object, ['*'], read=False)
2273 self.assert_write(any=True)
2275 def test_write_directory(self):
2276 dir_content_types = ('application/directory', 'application/foler')
2277 for type in dir_content_types:
2278 #change content type
2279 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2280 self.client.share_object(self.container, self.object, ['*'], read=False)
2281 self.assert_write(any=True)
2282 self.client.share_object(self.container, self.object, self.authorized, read=False)
2283 self.assert_write(authorized=self.authorized)
2284 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2285 self.assert_write(authorized=self.authorized)
2287 def test_shared_listing(self):
2288 self.client.share_object(self.container, self.object, self.authorized)
2290 my_shared_containers = self.client.list_containers(shared=True)
2291 self.assertEqual(['c'], my_shared_containers)
2292 my_shared_objects = self.client.list_objects('c', shared=True)
2293 self.assertEqual(['o'], my_shared_objects)
2295 dir_content_types = ('application/directory', 'application/foler')
2296 for type in dir_content_types:
2297 #change content type
2298 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2299 my_shared_objects = self.client.list_objects('c', shared=True)
2300 self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2302 for token, account in OTHER_ACCOUNTS.items():
2303 if account in self.authorized:
2304 self.other = Pithos_Client(get_url(), token, account)
2305 self.assertTrue(get_user() in self.other.list_shared_by_others())
2307 class TestPublish(BaseTestCase):
2308 def test_publish(self):
2309 self.client.create_container('c')
2310 o_data = self.upload_random_data('c', 'o')['data']
2311 self.client.publish_object('c', 'o')
2312 meta = self.client.retrieve_object_metadata('c', 'o')
2313 self.assertTrue('x-object-public' in meta)
2314 url = meta['x-object-public']
2316 p = urlparse(get_url())
2317 if p.scheme == 'http':
2318 conn = HTTPConnection(p.netloc)
2319 elif p.scheme == 'https':
2320 conn = HTTPSConnection(p.netloc)
2322 raise Exception('Unknown URL scheme')
2324 conn.request('GET', url)
2325 resp = conn.getresponse()
2326 length = resp.getheader('content-length', None)
2327 data = resp.read(length)
2328 self.assertEqual(o_data, data)
2330 class TestPolicies(BaseTestCase):
2331 def test_none_versioning(self):
2332 self.client.create_container('c', policies={'versioning':'none'})
2333 o = self.upload_random_data('c', 'o')
2334 meta = self.client.retrieve_object_metadata('c', 'o')
2335 v = meta['x-object-version']
2336 more_data = get_random_data()
2337 self.client.update_object('c', 'o', StringIO(more_data))
2338 vlist = self.client.retrieve_object_versionlist('c', 'o')
2339 self.assert_raises_fault(404, self.client.retrieve_object_version,
2341 data = self.client.retrieve_object('c', 'o')
2342 end = len(o['data'])
2343 self.assertEqual(data[:end], o['data'])
2344 self.assertEqual(data[end:], more_data)
2346 def test_quota(self):
2347 self.client.create_container('c', policies={'quota':'1'})
2348 meta = self.client.retrieve_container_metadata('c')
2349 self.assertEqual(meta['x-container-policy-quota'], '1')
2350 self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2353 def test_quota_none(self):
2354 self.client.create_container('c', policies={'quota':'0'})
2355 meta = self.client.retrieve_container_metadata('c')
2356 self.assertEqual(meta['x-container-policy-quota'], '0')
2357 self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2360 class AssertUUidInvariant(object):
2361 def __init__(self, callable, *args, **kwargs):
2362 self.callable = callable
2364 self.kwargs = kwargs
2366 def __enter__(self):
2367 self.map = self.callable(*self.args, **self.kwargs)
2368 assert('x-object-uuid' in self.map)
2369 self.uuid = self.map['x-object-uuid']
2372 def __exit__(self, type, value, tb):
2373 map = self.callable(*self.args, **self.kwargs)
2374 assert('x-object-uuid' in self.map)
2375 uuid = map['x-object-uuid']
2376 assert(uuid == self.uuid)
2378 class AssertMappingInvariant(object):
2379 def __init__(self, callable, *args, **kwargs):
2380 self.callable = callable
2382 self.kwargs = kwargs
2384 def __enter__(self):
2385 self.map = self.callable(*self.args, **self.kwargs)
2388 def __exit__(self, type, value, tb):
2389 map = self.callable(*self.args, **self.kwargs)
2390 for k, v in self.map.items():
2396 class AssertContentInvariant(object):
2397 def __init__(self, callable, *args, **kwargs):
2398 self.callable = callable
2400 self.kwargs = kwargs
2402 def __enter__(self):
2403 self.content = self.callable(*self.args, **self.kwargs)[2]
2406 def __exit__(self, type, value, tb):
2407 content = self.callable(*self.args, **self.kwargs)[2]
2408 assert self.content == content
2410 def get_content_splitted(response):
2412 return response.content.split('\n')
2414 def compute_md5_hash(data):
2418 return md5.hexdigest().lower()
2420 def compute_block_hash(data, algorithm):
2421 h = hashlib.new(algorithm)
2422 h.update(data.rstrip('\x00'))
2423 return h.hexdigest()
2425 def get_random_data(length=500):
2426 char_set = string.ascii_uppercase + string.digits
2427 return ''.join(random.choice(char_set) for x in xrange(length))
2430 MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2431 __D = r'(?P<day>\d{2})'
2432 __D2 = r'(?P<day>[ \d]\d)'
2433 __M = r'(?P<mon>\w{3})'
2434 __Y = r'(?P<year>\d{4})'
2435 __Y2 = r'(?P<year>\d{2})'
2436 __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2437 RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2438 RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2439 ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2440 for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2441 m = regex.match(date)
2446 def strnextling(prefix):
2447 """Return the first unicode string
2448 greater than but not starting with given prefix.
2449 strnextling('hello') -> 'hellp'
2452 ## all strings start with the null string,
2453 ## therefore we have to approximate strnextling('')
2454 ## with the last unicode character supported by python
2455 ## 0x10ffff for wide (32-bit unicode) python builds
2456 ## 0x00ffff for narrow (16-bit unicode) python builds
2457 ## We will not autodetect. 0xffff is safe enough.
2458 return unichr(0xffff)
2466 o_names = ['kate.jpg',
2467 'kate_beckinsale.jpg',
2468 'How To Win Friends And Influence People.pdf',
2469 'moms_birthday.jpg',
2471 'Disturbed - Down With The Sickness.mp3',
2472 'army_of_darkness.avi',
2474 'photos/animals/dogs/poodle.jpg',
2475 'photos/animals/dogs/terrier.jpg',
2476 'photos/animals/cats/persian.jpg',
2477 'photos/animals/cats/siamese.jpg',
2478 'photos/plants/fern.jpg',
2479 'photos/plants/rose.jpg',
2484 if get_user() == 'test':
2485 unittest.main(module='pithos.tools.test')
2487 print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2490 if __name__ == "__main__":