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():
121 #list objects returns at most 10000 objects
122 #so repeat until there are no more objects
123 objects = self.client.list_objects(c)
127 self.client.delete_object(c, o)
128 self.client.delete_container(c)
130 def assert_status(self, status, codes):
131 l = [elem for elem in self.return_codes]
132 if type(codes) == types.ListType:
136 self.assertTrue(status in l)
138 def assert_extended(self, data, format, type, size=10000):
140 self._assert_xml(data, type, size)
141 elif format == 'json':
142 self._assert_json(data, type, size)
144 def _assert_json(self, data, type, size):
145 convert = lambda s: s.lower()
146 info = [convert(elem) for elem in self.extended[type]]
147 self.assertTrue(len(data) <= size)
150 if 'subdir' in i.keys():
152 self.assertTrue(item in i.keys())
154 def _assert_xml(self, data, type, size):
155 convert = lambda s: s.lower()
156 info = [convert(elem) for elem in self.extended[type]]
158 info.remove('content_encoding')
162 entities = xml.getElementsByTagName(type)
163 self.assertTrue(len(entities) <= size)
166 self.assertTrue(e.getElementsByTagName(item))
168 def assert_raises_fault(self, status, callableObj, *args, **kwargs):
170 asserts that a Fault with a specific status is raised
171 when callableObj is called with the specific arguments
174 r = callableObj(*args, **kwargs)
175 self.fail('Should never reach here')
177 if type(status) == types.ListType:
178 self.failUnless(f.status in status)
180 self.failUnless(f.status == status)
182 def assert_not_raises_fault(self, status, callableObj, *args, **kwargs):
184 asserts that a Fault with a specific status is not raised
185 when callableObj is called with the specific arguments
188 r = callableObj(*args, **kwargs)
190 self.failIfEqual(f.status, status)
192 def assert_container_exists(self, container):
194 asserts the existence of a container
197 self.client.retrieve_container_metadata(container)
199 self.failIf(f.status == 404)
201 def assert_container_not_exists(self, container):
203 asserts there is no such a container
205 self.assert_raises_fault(404, self.client.retrieve_container_metadata,
208 def assert_object_exists(self, container, object):
210 asserts the existence of an object
213 self.client.retrieve_object_metadata(container, object)
215 self.failIf(f.status == 404)
217 def assert_object_not_exists(self, container, object):
219 asserts there is no such an object
221 self.assert_raises_fault(404, self.client.retrieve_object_metadata,
224 def assert_versionlist_structure(self, versionlist):
225 self.assertTrue(type(versionlist) == types.ListType)
226 for elem in versionlist:
227 self.assertTrue(type(elem) == types.ListType)
228 self.assertEqual(len(elem), 2)
230 def upload_random_data(self, container, name, length=1024, type=None,
232 data = get_random_data(length)
233 return self.upload_data(container, name, data, type, enc, **meta)
235 def upload_data(self, container, name, data, type=None, enc=None, etag=None,
241 obj['hash'] = compute_md5_hash(obj['data'])
244 args['etag'] = etag if etag else obj['hash']
247 guess = mimetypes.guess_type(name)
248 type = type if type else guess[0]
249 enc = enc if enc else guess[1]
252 args['content_type'] = type if type else 'plain/text'
253 args['content_encoding'] = enc if enc else None
257 path = '/%s/%s' % (container, name)
258 self.client.create_object(container, name, f=StringIO(obj['data']),
265 class AccountHead(BaseTestCase):
267 BaseTestCase.setUp(self)
268 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
269 for item in self.containers:
270 self.client.create_container(item)
273 self.client.update_account_metadata(**meta)
274 #self.updated_meta = self.initial_meta.update(meta)
276 def test_get_account_meta(self):
277 meta = self.client.retrieve_account_metadata()
279 containers = self.client.list_containers()
280 l = str(len(containers))
281 self.assertEqual(meta['x-account-container-count'], l)
284 m = self.client.retrieve_container_metadata(c)
285 size = size + int(m['x-container-bytes-used'])
286 self.assertEqual(meta['x-account-bytes-used'], str(size))
288 def test_get_account_403(self):
289 self.assert_raises_fault(403,
290 self.invalid_client.retrieve_account_metadata)
292 def test_get_account_meta_until(self):
293 t = datetime.datetime.utcnow()
294 past = t - datetime.timedelta(minutes=-15)
295 past = int(_time.mktime(past.timetuple()))
297 meta = {'premium':True}
298 self.client.update_account_metadata(**meta)
299 meta = self.client.retrieve_account_metadata(restricted=True,
301 self.assertTrue('premium' not in meta)
303 meta = self.client.retrieve_account_metadata(restricted=True)
304 self.assertTrue('premium' in meta)
306 def test_get_account_meta_until_invalid_date(self):
307 meta = {'premium':True}
308 self.client.update_account_metadata(**meta)
309 meta = self.client.retrieve_account_metadata(restricted=True,
311 self.assertTrue('premium' in meta)
313 class AccountGet(BaseTestCase):
315 BaseTestCase.setUp(self)
316 #create some containers
317 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
318 for item in self.containers:
319 self.client.create_container(item)
323 containers = self.client.list_containers()
324 self.assertEquals(self.containers, containers)
326 def test_list_403(self):
327 self.assert_raises_fault(403, self.invalid_client.list_containers)
329 def test_list_with_limit(self):
331 containers = self.client.list_containers(limit=limit)
332 self.assertEquals(len(containers), limit)
333 self.assertEquals(self.containers[:2], containers)
335 def test_list_with_marker(self):
338 containers = self.client.list_containers(limit=l, marker=m)
339 i = self.containers.index(m) + 1
340 self.assertEquals(self.containers[i:(i+l)], containers)
343 containers = self.client.list_containers(limit=l, marker=m)
344 i = self.containers.index(m) + 1
345 self.assertEquals(self.containers[i:(i+l)], containers)
347 def test_list_json_with_marker(self):
350 containers = self.client.list_containers(limit=l, marker=m, format='json')
351 self.assert_extended(containers, 'json', 'container', l)
352 self.assertEqual(containers[0]['name'], 'kiwis')
353 self.assertEqual(containers[1]['name'], 'oranges')
355 def test_list_xml_with_marker(self):
358 xml = self.client.list_containers(limit=l, marker=m, format='xml')
359 self.assert_extended(xml, 'xml', 'container', l)
360 nodes = xml.getElementsByTagName('name')
361 self.assertEqual(len(nodes), 1)
362 self.assertEqual(nodes[0].childNodes[0].data, 'pears')
364 def test_if_modified_since(self):
365 t = datetime.datetime.utcnow()
366 t2 = t - datetime.timedelta(minutes=10)
369 self.client.create_container('dummy')
371 for f in DATE_FORMATS:
372 past = t2.strftime(f)
374 c = self.client.list_containers(if_modified_since=past)
375 self.assertEqual(len(c), len(self.containers) + 1)
377 self.failIf(f.status == 304) #fail if not modified
380 def test_if_modified_since_invalid_date(self):
381 c = self.client.list_containers(if_modified_since='')
382 self.assertEqual(len(c), len(self.containers))
384 def test_if_not_modified_since(self):
385 now = datetime.datetime.utcnow()
386 since = now + datetime.timedelta(1)
388 for f in DATE_FORMATS:
389 args = {'if_modified_since':'%s' %since.strftime(f)}
392 self.assert_raises_fault(304, self.client.list_containers, **args)
394 def test_if_unmodified_since(self):
395 now = datetime.datetime.utcnow()
396 since = now + datetime.timedelta(1)
398 for f in DATE_FORMATS:
399 c = self.client.list_containers(if_unmodified_since=since.strftime(f))
402 self.assertEqual(self.containers, c)
404 def test_if_unmodified_since_precondition_failed(self):
405 t = datetime.datetime.utcnow()
406 t2 = t - datetime.timedelta(minutes=10)
409 self.client.create_container('dummy')
411 for f in DATE_FORMATS:
412 past = t2.strftime(f)
414 args = {'if_unmodified_since':'%s' %past}
416 #assert precondition failed
417 self.assert_raises_fault(412, self.client.list_containers, **args)
419 class AccountPost(BaseTestCase):
421 BaseTestCase.setUp(self)
422 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
423 for item in self.containers:
424 self.client.create_container(item)
427 self.client.update_account_metadata(**meta)
428 self.updated_meta = self.initial_meta.update(meta)
430 def test_update_meta(self):
431 with AssertMappingInvariant(self.client.retrieve_account_groups):
432 meta = {'test':'test', 'tost':'tost'}
433 self.client.update_account_metadata(**meta)
435 meta.update(self.initial_meta)
436 self.assertEqual(meta,
437 self.client.retrieve_account_metadata(
440 def test_invalid_account_update_meta(self):
441 meta = {'test':'test', 'tost':'tost'}
442 self.assert_raises_fault(403,
443 self.invalid_client.update_account_metadata,
446 def test_reset_meta(self):
447 with AssertMappingInvariant(self.client.retrieve_account_groups):
448 meta = {'test':'test', 'tost':'tost'}
449 self.client.update_account_metadata(**meta)
451 meta = {'test':'test33'}
452 self.client.reset_account_metadata(**meta)
454 self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
456 def test_delete_meta(self):
457 with AssertMappingInvariant(self.client.retrieve_account_groups):
458 meta = {'test':'test', 'tost':'tost'}
459 self.client.update_account_metadata(**meta)
461 self.client.delete_account_metadata(meta.keys())
463 account_meta = self.client.retrieve_account_metadata(restricted=True)
465 self.assertTrue(m not in account_meta.keys())
467 def test_set_account_groups(self):
468 with AssertMappingInvariant(self.client.retrieve_account_metadata):
469 groups = {'pithosdev':'verigak,gtsouk,chazapis'}
470 self.client.set_account_groups(**groups)
472 self.assertEqual(set(groups['pithosdev']),
473 set(self.client.retrieve_account_groups()['pithosdev']))
475 more_groups = {'clientsdev':'pkanavos,mvasilak'}
476 self.client.set_account_groups(**more_groups)
478 groups.update(more_groups)
479 self.assertEqual(set(groups['clientsdev']),
480 set(self.client.retrieve_account_groups()['clientsdev']))
482 def test_reset_account_groups(self):
483 with AssertMappingInvariant(self.client.retrieve_account_metadata):
484 groups = {'pithosdev':'verigak,gtsouk,chazapis',
485 'clientsdev':'pkanavos,mvasilak'}
486 self.client.set_account_groups(**groups)
488 self.assertEqual(set(groups['pithosdev'].split(',')),
489 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
490 self.assertEqual(set(groups['clientsdev'].split(',')),
491 set(self.client.retrieve_account_groups()['clientsdev'].split(',')))
493 groups = {'pithosdev':'verigak,gtsouk,chazapis,papagian'}
494 self.client.reset_account_groups(**groups)
496 self.assertEqual(set(groups['pithosdev'].split(',')),
497 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
499 def test_delete_account_groups(self):
500 with AssertMappingInvariant(self.client.retrieve_account_metadata):
501 groups = {'pithosdev':'verigak,gtsouk,chazapis',
502 'clientsdev':'pkanavos,mvasilak'}
503 self.client.set_account_groups(**groups)
505 self.client.unset_account_groups(groups.keys())
507 self.assertEqual({}, self.client.retrieve_account_groups())
509 class ContainerHead(BaseTestCase):
511 BaseTestCase.setUp(self)
512 self.container = 'apples'
513 self.client.create_container(self.container)
515 def test_get_meta(self):
516 meta = {'trash':'true'}
517 t1 = datetime.datetime.utcnow()
518 o = self.upload_random_data(self.container, o_names[0], **meta)
520 headers = self.client.retrieve_container_metadata(self.container)
521 self.assertEqual(headers['x-container-object-count'], '1')
522 self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
523 t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
525 threashold = datetime.timedelta(seconds=1)
526 self.assertTrue(delta < threashold)
527 self.assertTrue(headers['x-container-object-meta'])
528 self.assertTrue('Trash' in headers['x-container-object-meta'])
530 class ContainerGet(BaseTestCase):
532 BaseTestCase.setUp(self)
533 self.container = ['pears', 'apples']
534 for c in self.container:
535 self.client.create_container(c)
537 for o in o_names[:8]:
538 self.obj.append(self.upload_random_data(self.container[0], o))
539 for o in o_names[8:]:
540 self.obj.append(self.upload_random_data(self.container[1], o))
542 def test_list_objects(self):
543 objects = self.client.list_objects(self.container[0])
544 l = [elem['name'] for elem in self.obj[:8]]
546 self.assertEqual(objects, l)
548 def test_list_objects_containing_slash(self):
549 self.client.create_container('test')
550 self.upload_random_data('test', '/objectname')
552 objects = self.client.list_objects('test')
553 self.assertEqual(objects, ['/objectname'])
555 objects = self.client.list_objects('test', format='json')
556 self.assertEqual(objects[0]['name'], '/objectname')
558 objects = self.client.list_objects('test', format='xml')
559 self.assert_extended(objects, 'xml', 'object')
560 node_name = objects.getElementsByTagName('name')[0]
561 self.assertEqual(node_name.firstChild.data, '/objectname')
563 def test_list_objects_with_limit_marker(self):
564 objects = self.client.list_objects(self.container[0], limit=2)
565 l = [elem['name'] for elem in self.obj[:8]]
567 self.assertEqual(objects, l[:2])
569 markers = ['How To Win Friends And Influence People.pdf',
573 objects = self.client.list_objects(self.container[0], limit=limit,
575 l = [elem['name'] for elem in self.obj[:8]]
577 start = l.index(m) + 1
579 end = end if len(l) >= end else len(l)
580 self.assertEqual(objects, l[start:end])
583 def _test_list_limit_exceeds(self):
584 self.client.create_container('pithos')
586 for i in range(10001):
587 self.client.create_zero_length_object('pithos', i)
589 self.assertEqual(10000, len(self.client.list_objects('pithos')))
591 def test_list_empty_params(self):
592 objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
594 objects = objects.strip().split('\n')
595 self.assertEqual(objects,
596 self.client.list_objects(self.container[0]))
598 def test_list_pseudo_hierarchical_folders(self):
599 objects = self.client.list_objects(self.container[1], prefix='photos',
601 self.assertEquals(['photos/animals/', 'photos/me.jpg',
602 'photos/plants/'], objects)
604 objects = self.client.list_objects(self.container[1],
605 prefix='photos/animals',
607 l = ['photos/animals/cats/', 'photos/animals/dogs/']
608 self.assertEquals(l, objects)
610 objects = self.client.list_objects(self.container[1], path='photos')
611 self.assertEquals(['photos/me.jpg'], objects)
613 def test_extended_list_json(self):
614 objects = self.client.list_objects(self.container[1], format='json',
615 limit=2, prefix='photos/animals',
617 self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
618 self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
620 def test_extended_list_xml(self):
621 xml = self.client.list_objects(self.container[1], format='xml', limit=4,
622 prefix='photos', delimiter='/')
623 self.assert_extended(xml, 'xml', 'object', size=4)
624 dirs = xml.getElementsByTagName('subdir')
625 self.assertEqual(len(dirs), 2)
626 self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
627 self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
629 objects = xml.getElementsByTagName('name')
630 self.assertEqual(len(objects), 1)
631 self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
633 def test_list_meta_double_matching(self):
634 meta = {'quality':'aaa', 'stock':'true'}
635 self.client.update_object_metadata(self.container[0],
636 self.obj[0]['name'], **meta)
637 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
638 self.assertEqual(len(obj), 1)
639 self.assertTrue(obj, self.obj[0]['name'])
641 def test_list_using_meta(self):
642 meta = {'quality':'aaa'}
643 for o in self.obj[:2]:
644 self.client.update_object_metadata(self.container[0], o['name'],
646 meta = {'stock':'true'}
647 for o in self.obj[3:5]:
648 self.client.update_object_metadata(self.container[0], o['name'],
651 obj = self.client.list_objects(self.container[0], meta='Quality')
652 self.assertEqual(len(obj), 2)
653 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
655 # test case insensitive
656 obj = self.client.list_objects(self.container[0], meta='quality')
657 self.assertEqual(len(obj), 2)
658 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
660 # test multiple matches
661 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
662 self.assertEqual(len(obj), 4)
663 self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
665 # test non 1-1 multiple match
666 obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
667 self.assertEqual(len(obj), 2)
668 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
670 def test_if_modified_since(self):
671 t = datetime.datetime.utcnow()
672 t2 = t - datetime.timedelta(minutes=10)
675 self.upload_random_data(self.container[0], o_names[0])
677 for f in DATE_FORMATS:
678 past = t2.strftime(f)
680 o = self.client.list_objects(self.container[0],
681 if_modified_since=past)
683 self.client.list_objects(self.container[0]))
685 self.failIf(f.status == 304) #fail if not modified
687 def test_if_modified_since_invalid_date(self):
688 headers = {'if-modified-since':''}
689 o = self.client.list_objects(self.container[0], if_modified_since='')
690 self.assertEqual(o, self.client.list_objects(self.container[0]))
692 def test_if_not_modified_since(self):
693 now = datetime.datetime.utcnow()
694 since = now + datetime.timedelta(1)
696 for f in DATE_FORMATS:
697 args = {'if_modified_since':'%s' %since.strftime(f)}
700 self.assert_raises_fault(304, self.client.list_objects,
701 self.container[0], **args)
703 def test_if_unmodified_since(self):
704 now = datetime.datetime.utcnow()
705 since = now + datetime.timedelta(1)
707 for f in DATE_FORMATS:
708 obj = self.client.list_objects(self.container[0],
709 if_unmodified_since=since.strftime(f))
712 self.assertEqual(obj, self.client.list_objects(self.container[0]))
714 def test_if_unmodified_since_precondition_failed(self):
715 t = datetime.datetime.utcnow()
716 t2 = t - datetime.timedelta(minutes=10)
719 self.client.create_container('dummy')
721 for f in DATE_FORMATS:
722 past = t2.strftime(f)
724 args = {'if_unmodified_since':'%s' %past}
726 #assert precondition failed
727 self.assert_raises_fault(412, self.client.list_objects,
728 self.container[0], **args)
730 class ContainerPut(BaseTestCase):
732 BaseTestCase.setUp(self)
733 self.containers = ['c1', 'c2']
735 def test_create(self):
736 self.client.create_container(self.containers[0])
737 containers = self.client.list_containers()
738 self.assertTrue(self.containers[0] in containers)
739 self.assert_container_exists(self.containers[0])
741 def test_create_twice(self):
742 self.client.create_container(self.containers[0])
743 self.assertTrue(not self.client.create_container(self.containers[0]))
745 def test_quota(self):
746 self.client.create_container(self.containers[0])
748 policy = {'quota':100}
749 self.client.set_container_policies('c1', **policy)
751 meta = self.client.retrieve_container_metadata('c1')
752 self.assertTrue('x-container-policy-quota' in meta)
753 self.assertEqual(meta['x-container-policy-quota'], '100')
756 kwargs = {'length':101}
757 self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
761 self.client.set_container_policies('c1', **policy)
763 class ContainerPost(BaseTestCase):
765 BaseTestCase.setUp(self)
766 self.container = 'apples'
767 self.client.create_container(self.container)
769 def test_update_meta(self):
770 meta = {'test':'test33',
772 self.client.update_container_metadata(self.container, **meta)
773 headers = self.client.retrieve_container_metadata(self.container)
774 for k,v in meta.items():
775 k = 'x-container-meta-%s' % k
776 self.assertTrue(headers[k])
777 self.assertEqual(headers[k], v)
779 class ContainerDelete(BaseTestCase):
781 BaseTestCase.setUp(self)
782 self.containers = ['c1', 'c2']
783 for c in self.containers:
784 self.client.create_container(c)
786 def test_delete(self):
787 status = self.client.delete_container(self.containers[0])[0]
788 self.assertEqual(status, 204)
790 def test_delete_non_empty(self):
791 self.upload_random_data(self.containers[1], o_names[0])
792 self.assert_raises_fault(409, self.client.delete_container,
795 def test_delete_invalid(self):
796 self.assert_raises_fault(404, self.client.delete_container, 'c3')
798 class ObjectGet(BaseTestCase):
800 BaseTestCase.setUp(self)
801 self.containers = ['c1', 'c2']
802 #create some containers
803 for c in self.containers:
804 self.client.create_container(c)
807 names = ('obj1', 'obj2')
810 self.objects.append(self.upload_random_data(self.containers[1], n))
812 def test_versions(self):
813 c = self.containers[1]
815 b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
816 self.assert_versionlist_structure(b)
819 meta = {'quality':'AAA', 'stock':True}
820 self.client.update_object_metadata(c, o['name'], **meta)
822 a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
823 self.assert_versionlist_structure(a)
824 self.assertEqual(len(b)+1, len(a))
825 self.assertEqual(b, a[:-1])
827 #get exact previous version metadata
829 v_meta = self.client.retrieve_object_metadata(c, o['name'],
832 for k in meta.keys():
833 self.assertTrue(k not in v_meta)
836 data = get_random_data()
837 self.client.update_object(c, o['name'], StringIO(data))
839 aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
840 self.assert_versionlist_structure(aa)
841 self.assertEqual(len(a)+1, len(aa))
842 self.assertEqual(a, aa[:-1])
844 #get exact previous version
846 v_data = self.client.retrieve_object_version(c, o['name'], version=v)
847 self.assertEqual(o['data'], v_data)
848 self.assertEqual(self.client.retrieve_object(c, o['name']),
849 '%s%s' %(v_data, data))
853 o = self.client.retrieve_object(self.containers[1],
854 self.objects[0]['name'],
855 self.objects[0]['meta'])
856 self.assertEqual(o, self.objects[0]['data'])
858 def test_objects_with_trailing_spaces(self):
859 self.client.create_container('test')
861 self.upload_random_data('test', 'a')
862 #look for 'a ' object
863 self.assert_raises_fault(404, self.client.retrieve_object,
867 self.client.delete_object('test', 'a')
868 self.assert_raises_fault(404, self.client.retrieve_object,
872 self.upload_random_data('test', 'a ')
874 self.assert_raises_fault(404, self.client.retrieve_object,
877 def test_get_invalid(self):
878 self.assert_raises_fault(404, self.client.retrieve_object,
879 self.containers[0], self.objects[0]['name'])
881 def test_get_partial(self):
882 #perform get with range
883 status, headers, data = self.client.request_object(self.containers[1],
884 self.objects[0]['name'],
887 #assert successful partial content
888 self.assertEqual(status, 206)
891 self.assertEqual(headers['content-type'],
892 self.objects[0]['meta']['content_type'])
894 #assert content length
895 self.assertEqual(int(headers['content-length']), 500)
898 self.assertEqual(self.objects[0]['data'][:500], data)
900 def test_get_final_500(self):
901 #perform get with range
902 headers = {'range':'bytes=-500'}
903 status, headers, data = self.client.request_object(self.containers[1],
904 self.objects[0]['name'],
907 #assert successful partial content
908 self.assertEqual(status, 206)
911 self.assertEqual(headers['content-type'],
912 self.objects[0]['meta']['content_type'])
914 #assert content length
915 self.assertEqual(int(headers['content-length']), 500)
918 self.assertTrue(self.objects[0]['data'][-500:], data)
920 def test_get_rest(self):
921 #perform get with range
922 offset = len(self.objects[0]['data']) - 500
923 status, headers, data = self.client.request_object(self.containers[1],
924 self.objects[0]['name'],
925 range='bytes=%s-' %offset)
927 #assert successful partial content
928 self.assertEqual(status, 206)
931 self.assertEqual(headers['content-type'],
932 self.objects[0]['meta']['content_type'])
934 #assert content length
935 self.assertEqual(int(headers['content-length']), 500)
938 self.assertTrue(self.objects[0]['data'][-500:], data)
940 def test_get_range_not_satisfiable(self):
941 #perform get with range
942 offset = len(self.objects[0]['data']) + 1
944 #assert range not satisfiable
945 self.assert_raises_fault(416, self.client.retrieve_object,
946 self.containers[1], self.objects[0]['name'],
947 range='bytes=0-%s' %offset)
949 def test_multiple_range(self):
950 #perform get with multiple range
951 ranges = ['0-499', '-500', '1000-']
952 bytes = 'bytes=%s' % ','.join(ranges)
953 status, headers, data = self.client.request_object(self.containers[1],
954 self.objects[0]['name'],
957 # assert partial content
958 self.assertEqual(status, 206)
960 # assert Content-Type of the reply will be multipart/byteranges
961 self.assertTrue(headers['content-type'])
962 content_type_parts = headers['content-type'].split()
963 self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
965 boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
966 cparts = data.split(boundary)[1:-1]
968 # assert content parts are exactly 2
969 self.assertEqual(len(cparts), len(ranges))
971 # for each content part assert headers
974 content = cpart.split('\r\n')
975 headers = content[1:3]
976 content_range = headers[0].split(': ')
977 self.assertEqual(content_range[0], 'Content-Range')
979 r = ranges[i].split('-')
980 if not r[0] and not r[1]:
983 start = len(self.objects[0]['data']) - int(r[1])
984 end = len(self.objects[0]['data'])
987 end = len(self.objects[0]['data'])
991 fdata = self.objects[0]['data'][start:end]
992 sdata = '\r\n'.join(content[4:-1])
993 self.assertEqual(len(fdata), len(sdata))
994 self.assertEquals(fdata, sdata)
997 def test_multiple_range_not_satisfiable(self):
998 #perform get with multiple range
999 out_of_range = len(self.objects[0]['data']) + 1
1000 ranges = ['0-499', '-500', '%d-' %out_of_range]
1001 bytes = 'bytes=%s' % ','.join(ranges)
1003 # assert partial content
1004 self.assert_raises_fault(416, self.client.retrieve_object,
1006 self.objects[0]['name'], range=bytes)
1008 def test_get_with_if_match(self):
1009 #perform get with If-Match
1010 etag = self.objects[0]['hash']
1011 status, headers, data = self.client.request_object(self.containers[1],
1012 self.objects[0]['name'],
1015 self.assertEqual(status, 200)
1017 #assert content-type
1018 self.assertEqual(headers['content-type'],
1019 self.objects[0]['meta']['content_type'])
1021 #assert response content
1022 self.assertEqual(self.objects[0]['data'], data)
1024 def test_get_with_if_match_star(self):
1025 #perform get with If-Match *
1026 headers = {'if-match':'*'}
1027 status, headers, data = self.client.request_object(self.containers[1],
1028 self.objects[0]['name'],
1031 self.assertEqual(status, 200)
1033 #assert content-type
1034 self.assertEqual(headers['content-type'],
1035 self.objects[0]['meta']['content_type'])
1037 #assert response content
1038 self.assertEqual(self.objects[0]['data'], data)
1040 def test_get_with_multiple_if_match(self):
1041 #perform get with If-Match
1042 etags = [i['hash'] for i in self.objects if i]
1043 etags = ','.join('"%s"' % etag for etag in etags)
1044 status, headers, data = self.client.request_object(self.containers[1],
1045 self.objects[0]['name'],
1048 self.assertEqual(status, 200)
1050 #assert content-type
1051 self.assertEqual(headers['content-type'],
1052 self.objects[0]['meta']['content_type'])
1054 #assert content-type
1055 self.assertEqual(headers['content-type'],
1056 self.objects[0]['meta']['content_type'])
1058 #assert response content
1059 self.assertEqual(self.objects[0]['data'], data)
1061 def test_if_match_precondition_failed(self):
1062 #assert precondition failed
1063 self.assert_raises_fault(412, self.client.retrieve_object,
1065 self.objects[0]['name'], if_match='123')
1067 def test_if_none_match(self):
1068 #perform get with If-None-Match
1069 status, headers, data = self.client.request_object(self.containers[1],
1070 self.objects[0]['name'],
1071 if_none_match='123')
1074 self.assertEqual(status, 200)
1076 #assert content-type
1077 self.assertEqual(headers['content_type'],
1078 self.objects[0]['meta']['content_type'])
1080 def test_if_none_match(self):
1081 #perform get with If-None-Match * and assert not modified
1082 self.assert_raises_fault(304, self.client.retrieve_object,
1084 self.objects[0]['name'],
1087 def test_if_none_match_not_modified(self):
1088 #perform get with If-None-Match and assert not modified
1089 self.assert_raises_fault(304, self.client.retrieve_object,
1091 self.objects[0]['name'],
1092 if_none_match=self.objects[0]['hash'])
1094 meta = self.client.retrieve_object_metadata(self.containers[1],
1095 self.objects[0]['name'])
1096 self.assertEqual(meta['etag'], self.objects[0]['hash'])
1098 def test_if_modified_since(self):
1099 t = datetime.datetime.utcnow()
1100 t2 = t - datetime.timedelta(minutes=10)
1103 self.upload_data(self.containers[1],
1104 self.objects[0]['name'],
1105 self.objects[0]['data'][:200])
1107 for f in DATE_FORMATS:
1108 past = t2.strftime(f)
1110 headers = {'if-modified-since':'%s' %past}
1112 o = self.client.retrieve_object(self.containers[1],
1113 self.objects[0]['name'],
1114 if_modified_since=past)
1116 self.client.retrieve_object(self.containers[1],
1117 self.objects[0]['name']))
1119 self.failIf(f.status == 304)
1121 def test_if_modified_since_invalid_date(self):
1122 o = self.client.retrieve_object(self.containers[1],
1123 self.objects[0]['name'],
1124 if_modified_since='')
1125 self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1126 self.objects[0]['name']))
1128 def test_if_not_modified_since(self):
1129 now = datetime.datetime.utcnow()
1130 since = now + datetime.timedelta(1)
1132 for f in DATE_FORMATS:
1133 #assert not modified
1134 self.assert_raises_fault(304, self.client.retrieve_object,
1135 self.containers[1], self.objects[0]['name'],
1136 if_modified_since=since.strftime(f))
1138 def test_if_unmodified_since(self):
1139 now = datetime.datetime.utcnow()
1140 since = now + datetime.timedelta(1)
1142 for f in DATE_FORMATS:
1143 t = since.strftime(f)
1144 status, headers, data = self.client.request_object(self.containers[1],
1145 self.objects[0]['name'],
1146 if_unmodified_since=t)
1148 self.assertEqual(status, 200)
1149 self.assertEqual(self.objects[0]['data'], data)
1151 #assert content-type
1152 self.assertEqual(headers['content-type'],
1153 self.objects[0]['meta']['content_type'])
1155 def test_if_unmodified_since_precondition_failed(self):
1156 t = datetime.datetime.utcnow()
1157 t2 = t - datetime.timedelta(minutes=10)
1160 self.upload_data(self.containers[1],
1161 self.objects[0]['name'],
1162 self.objects[0]['data'][:200])
1164 for f in DATE_FORMATS:
1165 past = t2.strftime(f)
1166 #assert precondition failed
1167 self.assert_raises_fault(412, self.client.retrieve_object,
1168 self.containers[1], self.objects[0]['name'],
1169 if_unmodified_since=past)
1171 def test_hashes(self):
1174 o = self.upload_random_data(self.containers[1], fname, l)
1176 body = self.client.retrieve_object(self.containers[1], fname,
1178 hashes = body['hashes']
1179 block_size = body['block_size']
1180 block_hash = body['block_hash']
1181 block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1182 self.assertTrue(len(hashes), block_num)
1185 start = i * block_size
1186 end = (i + 1) * block_size
1187 hash = compute_block_hash(o['data'][start:end], block_hash)
1188 self.assertEqual(h, hash)
1191 class ObjectPut(BaseTestCase):
1193 BaseTestCase.setUp(self)
1194 self.container = 'c1'
1195 self.client.create_container(self.container)
1197 def test_upload(self):
1199 meta = {'test':'test1'}
1200 o = self.upload_random_data(self.container, name, **meta)
1202 headers = self.client.retrieve_object_metadata(self.container,
1205 self.assertTrue('test' in headers.keys())
1206 self.assertEqual(headers['test'], meta['test'])
1208 #assert uploaded content
1209 status, h, data = self.client.request_object(self.container, name)
1210 self.assertEqual(len(o['data']), int(h['content-length']))
1211 self.assertEqual(o['data'], data)
1213 #assert content-type
1214 self.assertEqual(h['content-type'], o['meta']['content_type'])
1216 def _test_maximum_upload_size_exceeds(self):
1218 meta = {'test':'test1'}
1220 length=1024*1024*100
1221 self.assert_raises_fault(400, self.upload_random_data, self.container,
1222 name, length, **meta)
1224 def test_upload_with_name_containing_slash(self):
1225 name = '/%s' % o_names[0]
1226 meta = {'test':'test1'}
1227 o = self.upload_random_data(self.container, name, **meta)
1229 self.assertEqual(o['data'],
1230 self.client.retrieve_object(self.container, name))
1232 self.assertTrue(name in self.client.list_objects(self.container))
1234 def test_create_directory_marker(self):
1235 self.client.create_directory_marker(self.container, 'foo')
1236 meta = self.client.retrieve_object_metadata(self.container, 'foo')
1237 self.assertEqual(meta['content-length'], '0')
1238 self.assertEqual(meta['content-type'], 'application/directory')
1240 def test_upload_unprocessable_entity(self):
1241 meta={'etag':'123', 'test':'test1'}
1243 #assert unprocessable entity
1244 self.assert_raises_fault(422, self.upload_random_data, self.container,
1247 def test_chunked_transfer(self):
1248 data = get_random_data()
1250 self.client.create_object_using_chunks(self.container, objname,
1253 uploaded_data = self.client.retrieve_object(self.container, objname)
1254 self.assertEqual(data, uploaded_data)
1256 def test_manifestation(self):
1257 prefix = 'myobject/'
1260 part = '%s%d' %(prefix, i)
1261 o = self.upload_random_data(self.container, part)
1264 manifest = '%s/%s' %(self.container, prefix)
1265 self.client.create_manifestation(self.container, 'large-object', manifest)
1267 self.assert_object_exists(self.container, 'large-object')
1268 self.assertEqual(data, self.client.retrieve_object(self.container,
1271 r = self.client.retrieve_object_hashmap(self.container,'large-object')
1272 hashes = r['hashes']
1273 block_size = int(r['block_size'])
1274 block_hash = r['block_hash']
1276 block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1277 self.assertEqual(block_num, len(hashes))
1279 #wrong manifestation
1280 self.client.create_manifestation(self.container, 'large-object',
1281 '%s/invalid' % self.container)
1282 self.assertEqual('', self.client.retrieve_object(self.container,
1285 def test_create_zero_length_object(self):
1288 zero = self.client.create_zero_length_object(c, o)
1289 zero_meta = self.client.retrieve_object_metadata(c, o)
1290 zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1291 zero_data = self.client.retrieve_object(c, o)
1293 self.assertEqual(int(zero_meta['content-length']), 0)
1294 hasher = newhasher('sha256')
1296 emptyhash = hasher.digest()
1297 self.assertEqual(zero_hash, [hexlify(emptyhash)])
1298 self.assertEqual(zero_data, '')
1300 def test_create_object_by_hashmap(self):
1303 self.upload_random_data(c, o)
1304 hashmap = self.client.retrieve_object(c, o, format='json')
1306 self.client.create_object_by_hashmap(c, o2, hashmap)
1307 self.assertEqual(self.client.retrieve_object(c, o),
1308 self.client.retrieve_object(c, o))
1310 class ObjectCopy(BaseTestCase):
1312 BaseTestCase.setUp(self)
1313 self.containers = ['c1', 'c2']
1314 for c in self.containers:
1315 self.client.create_container(c)
1316 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1318 def test_copy(self):
1319 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1320 self.containers[0], self.obj['name']):
1322 meta = {'test':'testcopy'}
1323 status = self.client.copy_object(self.containers[0],
1329 #assert copy success
1330 self.assertEqual(status, 201)
1332 #assert access the new object
1333 headers = self.client.retrieve_object_metadata(self.containers[0],
1335 self.assertTrue('x-object-meta-test' in headers.keys())
1336 self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1338 #assert etag is the same
1339 self.assertEqual(headers['etag'], self.obj['hash'])
1341 #assert src object still exists
1342 self.assert_object_exists(self.containers[0], self.obj['name'])
1344 def test_copy_from_different_container(self):
1345 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1346 self.containers[0], self.obj['name']):
1347 meta = {'test':'testcopy'}
1348 status = self.client.copy_object(self.containers[0],
1353 self.assertEqual(status, 201)
1355 # assert updated metadata
1356 meta = self.client.retrieve_object_metadata(self.containers[1],
1359 self.assertTrue('test' in meta.keys())
1360 self.assertTrue(meta['test'], 'testcopy')
1362 #assert src object still exists
1363 self.assert_object_exists(self.containers[0], self.obj['name'])
1365 def test_copy_invalid(self):
1366 #copy from invalid object
1367 meta = {'test':'testcopy'}
1368 self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1369 'test.py', self.containers[1], 'testcopy', meta)
1371 #copy from invalid container
1372 meta = {'test':'testcopy'}
1373 self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1374 self.obj['name'], self.containers[1],
1377 class ObjectMove(BaseTestCase):
1379 BaseTestCase.setUp(self)
1380 self.containers = ['c1', 'c2']
1381 for c in self.containers:
1382 self.client.create_container(c)
1383 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1385 def test_move(self):
1386 meta = self.client.retrieve_object_metadata(self.containers[0],
1388 self.assertTrue('x-object-uuid' in meta)
1389 uuid = meta['x-object-uuid']
1392 meta = {'test':'testcopy'}
1393 src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1394 status = self.client.move_object(self.containers[0], self.obj['name'],
1395 self.containers[0], 'testcopy',
1398 #assert successful move
1399 self.assertEqual(status, 201)
1401 #assert updated metadata
1402 meta = self.client.retrieve_object_metadata(self.containers[0],
1404 self.assertTrue('x-object-meta-test' in meta.keys())
1405 self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1408 self.assertTrue(meta['x-object-uuid'], uuid)
1410 #assert src object no more exists
1411 self.assert_object_not_exists(self.containers[0], self.obj['name'])
1413 class ObjectPost(BaseTestCase):
1415 BaseTestCase.setUp(self)
1416 self.containers = ['c1', 'c2']
1417 for c in self.containers:
1418 self.client.create_container(c)
1421 self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1423 def test_update_meta(self):
1424 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1426 self.obj[0]['name']):
1427 #perform update metadata
1428 more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1429 status = self.client.update_object_metadata(self.containers[0],
1430 self.obj[0]['name'],
1432 #assert request accepted
1433 self.assertEqual(status, 202)
1435 #assert old metadata are still there
1436 headers = self.client.retrieve_object_metadata(self.containers[0],
1437 self.obj[0]['name'],
1439 #assert new metadata have been updated
1440 for k,v in more.items():
1441 self.assertTrue(k in headers.keys())
1442 self.assertTrue(headers[k], v)
1445 more = {'f' * 114: 'b' * 257}
1446 self.assert_raises_fault(400, self.client.update_object_metadata,
1448 self.obj[0]['name'],
1451 #perform update metadata
1452 more = {'α': 'β' * 256}
1453 status = self.client.update_object_metadata(self.containers[0],
1454 self.obj[0]['name'],
1456 #assert request accepted
1457 self.assertEqual(status, 202)
1459 #assert old metadata are still there
1460 headers = self.client.retrieve_object_metadata(self.containers[0],
1461 self.obj[0]['name'],
1463 #assert new metadata have been updated
1464 for k,v in more.items():
1465 self.assertTrue(k in headers.keys())
1466 self.assertTrue(headers[k], v)
1469 more = {'α': 'β' * 257}
1470 self.assert_raises_fault(400, self.client.update_object_metadata,
1472 self.obj[0]['name'],
1475 def test_update_object(self,
1478 instance_length = True,
1479 content_length = 500):
1480 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1482 self.obj[0]['name']):
1483 l = len(self.obj[0]['data'])
1484 range = 'bytes %d-%d/%s' %(first_byte_pos,
1486 l if instance_length else '*')
1487 partial = last_byte_pos - first_byte_pos + 1
1488 length = first_byte_pos + partial
1489 data = get_random_data(partial)
1490 args = {'content_type':'application/octet-stream',
1491 'content_range':'%s' %range}
1493 args['content_length'] = content_length
1495 r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1496 StringIO(data), **args)
1499 if partial < 0 or (instance_length and l <= last_byte_pos):
1500 self.assertEqual(status, 202)
1502 self.assertEqual(status, 204)
1503 #check modified object
1504 content = self.client.retrieve_object(self.containers[0],
1505 self.obj[0]['name'])
1506 self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1507 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1508 self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1509 self.assertEqual(etag, compute_md5_hash(content))
1511 def test_update_object_lt_blocksize(self):
1512 self.test_update_object(10, 20, content_length=None)
1514 def test_update_object_gt_blocksize(self):
1515 o = self.upload_random_data(self.containers[0], o_names[1],
1516 length=4*1024*1024+5)
1517 c = self.containers[0]
1520 first_byte_pos = 4*1024*1024+1
1521 last_byte_pos = 4*1024*1024+4
1522 l = last_byte_pos - first_byte_pos + 1
1523 data = get_random_data(l)
1524 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1525 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1526 content = self.client.retrieve_object(c, o_name)
1527 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1528 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1529 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1531 def test_update_object_divided_by_blocksize(self):
1532 o = self.upload_random_data(self.containers[0], o_names[1],
1533 length=4*1024*1024+5)
1534 c = self.containers[0]
1537 first_byte_pos = 4*1024*1024
1538 last_byte_pos = 5*1024*1024
1539 l = last_byte_pos - first_byte_pos + 1
1540 data = get_random_data(l)
1541 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1542 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1543 content = self.client.retrieve_object(c, o_name)
1544 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1545 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1546 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1548 def test_update_object_no_content_length(self):
1549 self.test_update_object(content_length = None)
1551 def test_update_object_invalid_content_length(self):
1552 with AssertContentInvariant(self.client.retrieve_object,
1553 self.containers[0], self.obj[0]['name']):
1554 self.assert_raises_fault(400, self.test_update_object,
1555 content_length = 1000)
1557 def _test_update_object_invalid_range(self):
1558 with AssertContentInvariant(self.client.retrieve_object,
1559 self.containers[0], self.obj[0]['name']):
1560 self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1562 def _test_update_object_invalid_range_and_length(self):
1563 with AssertContentInvariant(self.client.retrieve_object,
1564 self.containers[0], self.obj[0]['name']):
1565 self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1568 def test_update_object_invalid_range_with_no_content_length(self):
1569 with AssertContentInvariant(self.client.retrieve_object,
1570 self.containers[0], self.obj[0]['name']):
1571 self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1572 content_length = None)
1574 def test_update_object_out_of_limits(self):
1575 with AssertContentInvariant(self.client.retrieve_object,
1576 self.containers[0], self.obj[0]['name']):
1577 l = len(self.obj[0]['data'])
1578 self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1580 def test_append(self):
1581 data = get_random_data(500)
1583 self.client.update_object(self.containers[0], self.obj[0]['name'],
1584 StringIO(data), content_length=500,
1585 content_type='application/octet-stream')
1587 content = self.client.retrieve_object(self.containers[0],
1588 self.obj[0]['name'])
1589 self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1590 self.assertEqual(content[:-500], self.obj[0]['data'])
1592 def test_update_with_chunked_transfer(self):
1593 data = get_random_data(500)
1595 fl = len(self.obj[0]['data'])
1597 self.client.update_object_using_chunks(self.containers[0],
1598 self.obj[0]['name'],
1601 content_type='application/octet-stream')
1603 #check modified object
1604 content = self.client.retrieve_object(self.containers[0],
1605 self.obj[0]['name'])
1606 self.assertEqual(content[0:dl], data)
1607 self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1609 def test_update_from_other_object(self):
1610 c = self.containers[0]
1614 source_data = self.client.retrieve_object(c, src)
1615 source_meta = self.client.retrieve_object_metadata(c, src)
1616 source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1618 #update zero length object
1619 self.client.create_zero_length_object(c, dest)
1620 source_object = '/%s/%s' % (c, src)
1621 self.client.update_from_other_source(c, dest, source_object)
1622 dest_data = self.client.retrieve_object(c, src)
1623 dest_meta = self.client.retrieve_object_metadata(c, dest)
1624 dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1625 self.assertEqual(source_data, dest_data)
1626 self.assertEqual(source_hash, dest_hash)
1629 self.client.update_from_other_source(c, dest, source_object)
1630 content = self.client.retrieve_object(c, dest)
1631 self.assertEqual(source_data * 2, content)
1633 def test_update_range_from_other_object(self):
1634 c = self.containers[0]
1638 src = self.obj[1]['name']
1639 src_data = self.client.retrieve_object(c, src)
1641 #update zero length object
1642 prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1643 source_object = '/%s/%s' % (c, src)
1644 first_byte_pos = 4*1024*1024+1
1645 last_byte_pos = 4*1024*1024+4
1646 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1647 self.client.update_from_other_source(c, dest, source_object,
1648 content_range=range)
1649 content = self.client.retrieve_object(c, dest)
1650 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1651 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1652 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1654 def test_update_hashes_from_other_object(self):
1655 c = self.containers[0]
1659 src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1661 #update zero length object
1662 prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1663 source_object = '/%s/%s' % (c, o_names[0])
1664 first_byte_pos = 4*1024*1024
1665 last_byte_pos = 5*1024*1024
1666 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1667 self.client.update_from_other_source(c, dest, source_object,
1668 content_range=range)
1669 content = self.client.retrieve_object(c, dest)
1670 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1671 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1672 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1675 def test_update_zero_length_object(self):
1676 c = self.containers[0]
1679 zero = self.client.create_zero_length_object(c, o)
1681 data = get_random_data()
1682 self.client.update_object(c, o, StringIO(data))
1683 self.client.create_object(c, other, StringIO(data))
1685 self.assertEqual(self.client.retrieve_object(c, o),
1686 self.client.retrieve_object(c, other))
1688 self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1689 self.client.retrieve_object_hashmap(c, other)["hashes"])
1691 class ObjectDelete(BaseTestCase):
1693 BaseTestCase.setUp(self)
1694 self.containers = ['c1', 'c2']
1695 for c in self.containers:
1696 self.client.create_container(c)
1697 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1699 def test_delete(self):
1700 #perform delete object
1701 self.client.delete_object(self.containers[0], self.obj['name'])[0]
1703 def test_delete_invalid(self):
1704 #assert item not found
1705 self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1708 class ListSharing(BaseTestCase):
1710 BaseTestCase.setUp(self)
1712 self.client.create_container('c%s' %i)
1713 self.client.create_container('c')
1715 self.upload_random_data('c1', 'o%s' %i)
1716 accounts = OTHER_ACCOUNTS.copy()
1717 self.o1_sharing_with = accounts.popitem()
1718 self.o1_sharing = [self.o1_sharing_with[1]]
1719 self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1723 l.append(accounts.popitem())
1725 def test_list_other_shared(self):
1726 self.other = Pithos_Client(get_url(),
1727 self.o1_sharing_with[0],
1728 self.o1_sharing_with[1])
1729 self.assertTrue(get_user() in self.other.list_shared_by_others())
1731 def test_list_my_shared(self):
1732 my_shared_containers = self.client.list_containers(shared=True)
1733 self.assertTrue('c1' in my_shared_containers)
1734 self.assertTrue('c2' not in my_shared_containers)
1736 my_shared_objects = self.client.list_objects('c1', shared=True)
1737 self.assertTrue('o1' in my_shared_objects)
1738 self.assertTrue('o2' not in my_shared_objects)
1740 class List(BaseTestCase):
1742 BaseTestCase.setUp(self)
1743 for i in range(1, 5):
1745 self.client.create_container(c)
1746 for j in range(1, 3):
1748 self.upload_random_data(c, o)
1750 self.client.share_object(c, 'o1', ['papagian'], read=True)
1752 self.client.publish_object(c, 'o2')
1754 def test_shared_public(self):
1755 self.assertEqual(self.client.list_containers(shared=True),
1757 self.assertEqual(self.client.list_containers(public=True), ['c1', 'c3'])
1758 self.assertEqual(self.client.list_containers(shared=True, public=True), ['c1', 'c2', 'c3'])
1760 self.assertEqual(self.client.list_objects('c1', shared=True), ['o1'])
1761 self.assertEqual(self.client.list_objects('c1', public=True), ['o2'])
1762 self.assertEqual(self.client.list_objects('c1', shared=True, public=True), ['o1', 'o2'])
1764 self.assertEqual(self.client.list_objects('c2', shared=True), ['o1'])
1765 self.assertEqual(self.client.list_objects('c2', public=True), '')
1766 self.assertEqual(self.client.list_objects('c2', shared=True, public=True), ['o1'])
1768 self.assertEqual(self.client.list_objects('c3', shared=True), '')
1769 self.assertEqual(self.client.list_objects('c3', public=True), ['o2'])
1770 self.assertEqual(self.client.list_objects('c3', shared=True, public=True), ['o2'])
1772 self.assertEqual(self.client.list_objects('c4', shared=True), '')
1773 self.assertEqual(self.client.list_objects('c4', public=True), '')
1774 self.assertEqual(self.client.list_objects('c4', shared=True, public=True), '')
1776 class TestGreek(BaseTestCase):
1777 def test_create_container(self):
1778 self.client.create_container('φάκελος')
1779 self.assert_container_exists('φάκελος')
1781 self.assertTrue('φάκελος' in self.client.list_containers())
1783 def test_create_object(self):
1784 self.client.create_container('φάκελος')
1785 self.upload_random_data('φάκελος', 'αντικείμενο')
1787 self.assert_object_exists('φάκελος', 'αντικείμενο')
1788 self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1790 def test_copy_object(self):
1791 src_container = 'φάκελος'
1792 src_object = 'αντικείμενο'
1793 dest_container = 'αντίγραφα'
1794 dest_object = 'ασφαλές-αντίγραφο'
1796 self.client.create_container(src_container)
1797 self.upload_random_data(src_container, src_object)
1799 self.client.create_container(dest_container)
1800 self.client.copy_object(src_container, src_object, dest_container,
1803 self.assert_object_exists(src_container, src_object)
1804 self.assert_object_exists(dest_container, dest_object)
1805 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1807 def test_move_object(self):
1808 src_container = 'φάκελος'
1809 src_object = 'αντικείμενο'
1810 dest_container = 'αντίγραφα'
1811 dest_object = 'ασφαλές-αντίγραφο'
1813 self.client.create_container(src_container)
1814 self.upload_random_data(src_container, src_object)
1816 self.client.create_container(dest_container)
1817 self.client.move_object(src_container, src_object, dest_container,
1820 self.assert_object_not_exists(src_container, src_object)
1821 self.assert_object_exists(dest_container, dest_object)
1822 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1824 def test_delete_object(self):
1825 self.client.create_container('φάκελος')
1826 self.upload_random_data('φάκελος', 'αντικείμενο')
1827 self.assert_object_exists('φάκελος', 'αντικείμενο')
1829 self.client.delete_object('φάκελος', 'αντικείμενο')
1830 self.assert_object_not_exists('φάκελος', 'αντικείμενο')
1831 self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
1833 def test_delete_container(self):
1834 self.client.create_container('φάκελος')
1835 self.assert_container_exists('φάκελος')
1837 self.client.delete_container('φάκελος')
1838 self.assert_container_not_exists('φάκελος')
1839 self.assertTrue('φάκελος' not in self.client.list_containers())
1841 def test_account_meta(self):
1842 meta = {'ποιότητα':'ΑΑΑ'}
1843 self.client.update_account_metadata(**meta)
1844 meta = self.client.retrieve_account_metadata(restricted=True)
1845 self.assertTrue('ποιότητα' in meta.keys())
1846 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1848 def test_container_meta(self):
1849 meta = {'ποιότητα':'ΑΑΑ'}
1850 self.client.create_container('φάκελος', meta=meta)
1852 meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
1853 self.assertTrue('ποιότητα' in meta.keys())
1854 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1856 def test_object_meta(self):
1857 self.client.create_container('φάκελος')
1858 meta = {'ποιότητα':'ΑΑΑ'}
1859 self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
1861 meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
1863 self.assertTrue('ποιότητα' in meta.keys())
1864 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1866 def test_list_meta_filtering(self):
1867 self.client.create_container('φάκελος')
1868 meta = {'ποιότητα':'ΑΑΑ'}
1869 self.upload_random_data('φάκελος', 'ο1', **meta)
1870 self.upload_random_data('φάκελος', 'ο2')
1871 self.upload_random_data('φάκελος', 'ο3')
1873 meta = {'ποσότητα':'μεγάλη'}
1874 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1875 objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
1876 self.assertEquals(objects, ['ο1', 'ο2'])
1878 objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
1879 self.assertEquals(objects, ['ο2', 'ο3'])
1881 objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
1882 self.assertEquals(objects, ['ο3'])
1884 meta = {'ποιότητα':'ΑΒ'}
1885 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1886 objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
1887 self.assertEquals(objects, ['ο1'])
1888 objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
1889 self.assertEquals(objects, ['ο2'])
1891 meta = {'έτος':'2011'}
1892 self.client.update_object_metadata('φάκελος', 'ο3', **meta)
1893 meta = {'έτος':'2012'}
1894 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1895 objects = self.client.list_objects('φάκελος', meta='έτος<2012')
1896 self.assertEquals(objects, ['ο3'])
1897 objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
1898 self.assertEquals(objects, ['ο2', 'ο3'])
1899 objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
1900 self.assertEquals(objects, '')
1902 def test_groups(self):
1904 groups = {'σεφς':'chazapis,διογένης'}
1905 self.client.set_account_groups(**groups)
1906 groups.update(self.initial_groups)
1907 self.assertEqual(groups['σεφς'],
1908 self.client.retrieve_account_groups()['σεφς'])
1911 self.client.create_container('φάκελος')
1912 o = self.upload_random_data('φάκελος', 'ο1')
1913 self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
1914 chef = Pithos_Client(get_url(),
1917 self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
1918 'φάκελος', 'ο1', account=get_user())
1921 self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
1922 new_data = get_random_data()
1923 self.assert_not_raises_fault(403, chef.update_object,
1924 'φάκελος', 'ο1', StringIO(new_data),
1927 server_data = self.client.retrieve_object('φάκελος', 'ο1')
1928 self.assertEqual(server_data[:len(o['data'])], o['data'])
1929 self.assertEqual(server_data[len(o['data']):], new_data)
1931 def test_manifestation(self):
1932 self.client.create_container('κουβάς')
1936 part = '%s%d' %(prefix, i)
1937 o = self.upload_random_data('κουβάς', part)
1940 self.client.create_container('φάκελος')
1941 manifest = '%s/%s' %('κουβάς', prefix)
1942 self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
1944 self.assert_object_exists('φάκελος', 'άπαντα')
1945 self.assertEqual(data, self.client.retrieve_object('φάκελος',
1948 #wrong manifestation
1949 self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
1950 self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
1952 def test_update_from_another_object(self):
1953 self.client.create_container('κουβάς')
1954 src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
1955 initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
1956 source_object = '/%s/%s' % ('κουβάς', 'πηγή')
1957 self.client.update_from_other_source('κουβάς', 'νέο', source_object)
1960 self.client.retrieve_object('κουβάς', 'νέο'),
1961 '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
1963 class TestPermissions(BaseTestCase):
1965 BaseTestCase.setUp(self)
1968 self.authorized = ['chazapis', 'verigak', 'gtsouk']
1969 groups = {'pithosdev':','.join(self.authorized)}
1970 self.client.set_account_groups(**groups)
1972 self.container = 'c'
1974 self.client.create_container(self.container)
1975 self.upload_random_data(self.container, self.object)
1976 self.upload_random_data(self.container, self.object+'/')
1977 self.upload_random_data(self.container, self.object+'/a')
1978 self.upload_random_data(self.container, self.object+'a')
1979 self.upload_random_data(self.container, self.object+'a/')
1980 self.dir_content_types = ('application/directory', 'application/folder')
1982 def assert_read(self, authorized=[], any=False, depth=0):
1983 for token, account in OTHER_ACCOUNTS.items():
1984 cl = Pithos_Client(get_url(), token, account)
1985 if account in authorized or any:
1986 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
1987 self.container, self.object,
1990 self.assert_raises_fault(403, cl.retrieve_object_metadata,
1991 self.container, self.object,
1995 meta = self.client.retrieve_object_metadata(self.container, self.object)
1996 type = meta['content-type']
1997 derivatives = self.client.list_objects(self.container, prefix=self.object)
1998 #exclude the self.object
1999 del derivatives[derivatives.index(self.object)]
2000 for o in derivatives:
2001 for token, account in OTHER_ACCOUNTS.items():
2002 cl = Pithos_Client(get_url(), token, account)
2003 prefix = self.object if self.object.endswith('/') else self.object+'/'
2004 if (account in authorized or any) and \
2005 (type in self.dir_content_types) and \
2006 o.startswith(prefix):
2007 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2008 self.container, o, account=get_user())
2010 self.assert_raises_fault(403, cl.retrieve_object_metadata,
2011 self.container, o, account=get_user())
2013 def assert_write(self, authorized=[], any=False):
2014 o_data = self.client.retrieve_object(self.container, self.object)
2015 for token, account in OTHER_ACCOUNTS.items():
2016 cl = Pithos_Client(get_url(), token, account)
2017 new_data = get_random_data()
2018 if account in authorized or any:
2020 self.assert_not_raises_fault(403, cl.update_object,
2021 self.container, self.object, StringIO(new_data),
2025 server_data = cl.retrieve_object(self.container, self.object, account=get_user())
2026 self.assertEqual(o_data, server_data[:len(o_data)])
2027 self.assertEqual(new_data, server_data[len(o_data):])
2028 o_data = server_data
2030 self.failIf(f.status == 403)
2032 self.assert_raises_fault(403, cl.update_object,
2033 self.container, self.object, StringIO(new_data),
2036 meta = self.client.retrieve_object_metadata(self.container, self.object)
2037 type = meta['content-type']
2038 derivatives = self.client.list_objects(self.container, prefix=self.object)
2040 del derivatives[derivatives.index(self.object)]
2041 for o in derivatives:
2042 for token, account in OTHER_ACCOUNTS.items():
2043 prefix = self.object if self.object.endswith('/') else self.object+'/'
2044 cl = Pithos_Client(get_url(), token, account)
2045 new_data = get_random_data()
2046 if (account in authorized or any) and \
2047 (type in self.dir_content_types) and \
2048 o.startswith(prefix):
2050 self.assert_not_raises_fault(403, cl.update_object,
2055 server_data = cl.retrieve_object(self.container, o, account=get_user())
2056 self.assertEqual(new_data, server_data[-len(new_data):])
2058 self.failIf(f.status == 403)
2060 self.assert_raises_fault(403, cl.update_object,
2065 def test_group_read(self):
2066 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2067 self.assert_read(authorized=self.authorized)
2069 def test_read_many(self):
2070 self.client.share_object(self.container, self.object, self.authorized)
2071 self.assert_read(authorized=self.authorized)
2073 def test_read_by_everyone(self):
2074 self.client.share_object(self.container, self.object, ['*'])
2075 self.assert_read(any=True)
2077 def test_read_directory(self):
2078 for type in self.dir_content_types:
2079 #change content type
2080 self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2081 self.client.share_object(self.container, self.object, ['*'])
2082 self.assert_read(any=True)
2083 self.client.share_object(self.container, self.object, self.authorized)
2084 self.assert_read(authorized=self.authorized)
2085 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2086 self.assert_read(authorized=self.authorized)
2088 def test_group_write(self):
2089 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2090 self.assert_write(authorized=self.authorized)
2092 def test_write_many(self):
2093 self.client.share_object(self.container, self.object, self.authorized, read=False)
2094 self.assert_write(authorized=self.authorized)
2096 def test_write_by_everyone(self):
2097 self.client.share_object(self.container, self.object, ['*'], read=False)
2098 self.assert_write(any=True)
2100 def test_write_directory(self):
2101 dir_content_types = ('application/directory', 'application/foler')
2102 for type in dir_content_types:
2103 #change content type
2104 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2105 self.client.share_object(self.container, self.object, ['*'], read=False)
2106 self.assert_write(any=True)
2107 self.client.share_object(self.container, self.object, self.authorized, read=False)
2108 self.assert_write(authorized=self.authorized)
2109 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2110 self.assert_write(authorized=self.authorized)
2112 def test_shared_listing(self):
2113 self.client.share_object(self.container, self.object, self.authorized)
2115 my_shared_containers = self.client.list_containers(shared=True)
2116 self.assertEqual(['c'], my_shared_containers)
2117 my_shared_objects = self.client.list_objects('c', shared=True)
2118 self.assertEqual(['o'], my_shared_objects)
2120 dir_content_types = ('application/directory', 'application/foler')
2121 for type in dir_content_types:
2122 #change content type
2123 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2124 my_shared_objects = self.client.list_objects('c', shared=True)
2125 self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2127 for token, account in OTHER_ACCOUNTS.items():
2128 if account in self.authorized:
2129 self.other = Pithos_Client(get_url(), token, account)
2130 self.assertTrue(get_user() in self.other.list_shared_by_others())
2132 class TestPublish(BaseTestCase):
2133 def test_publish(self):
2134 self.client.create_container('c')
2135 o_data = self.upload_random_data('c', 'o')['data']
2136 self.client.publish_object('c', 'o')
2137 meta = self.client.retrieve_object_metadata('c', 'o')
2138 self.assertTrue('x-object-public' in meta)
2139 url = meta['x-object-public']
2141 p = urlparse(get_url())
2142 if p.scheme == 'http':
2143 conn = HTTPConnection(p.netloc)
2144 elif p.scheme == 'https':
2145 conn = HTTPSConnection(p.netloc)
2147 raise Exception('Unknown URL scheme')
2149 conn.request('GET', url)
2150 resp = conn.getresponse()
2151 length = resp.getheader('content-length', None)
2152 data = resp.read(length)
2153 self.assertEqual(o_data, data)
2155 class TestPolicies(BaseTestCase):
2156 def test_none_versioning(self):
2157 self.client.create_container('c', policies={'versioning':'none'})
2158 o = self.upload_random_data('c', 'o')
2159 meta = self.client.retrieve_object_metadata('c', 'o')
2160 v = meta['x-object-version']
2161 more_data = get_random_data()
2162 self.client.update_object('c', 'o', StringIO(more_data))
2163 vlist = self.client.retrieve_object_versionlist('c', 'o')
2164 self.assert_raises_fault(404, self.client.retrieve_object_version,
2166 data = self.client.retrieve_object('c', 'o')
2167 end = len(o['data'])
2168 self.assertEqual(data[:end], o['data'])
2169 self.assertEqual(data[end:], more_data)
2171 def test_quota(self):
2172 self.client.create_container('c', policies={'quota':'1'})
2173 meta = self.client.retrieve_container_metadata('c')
2174 self.assertEqual(meta['x-container-policy-quota'], '1')
2175 self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2178 def test_quota_none(self):
2179 self.client.create_container('c', policies={'quota':'0'})
2180 meta = self.client.retrieve_container_metadata('c')
2181 self.assertEqual(meta['x-container-policy-quota'], '0')
2182 self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2185 class AssertUUidInvariant(object):
2186 def __init__(self, callable, *args, **kwargs):
2187 self.callable = callable
2189 self.kwargs = kwargs
2191 def __enter__(self):
2192 self.map = self.callable(*self.args, **self.kwargs)
2193 assert('x-object-uuid' in self.map)
2194 self.uuid = self.map['x-object-uuid']
2197 def __exit__(self, type, value, tb):
2198 map = self.callable(*self.args, **self.kwargs)
2199 assert('x-object-uuid' in self.map)
2200 uuid = map['x-object-uuid']
2201 assert(uuid == self.uuid)
2203 class AssertMappingInvariant(object):
2204 def __init__(self, callable, *args, **kwargs):
2205 self.callable = callable
2207 self.kwargs = kwargs
2209 def __enter__(self):
2210 self.map = self.callable(*self.args, **self.kwargs)
2213 def __exit__(self, type, value, tb):
2214 map = self.callable(*self.args, **self.kwargs)
2215 for k, v in self.map.items():
2218 #print '#', k, v, map[k]
2222 class AssertContentInvariant(object):
2223 def __init__(self, callable, *args, **kwargs):
2224 self.callable = callable
2226 self.kwargs = kwargs
2228 def __enter__(self):
2229 self.content = self.callable(*self.args, **self.kwargs)[2]
2232 def __exit__(self, type, value, tb):
2233 content = self.callable(*self.args, **self.kwargs)[2]
2234 assert self.content == content
2236 def get_content_splitted(response):
2238 return response.content.split('\n')
2240 def compute_md5_hash(data):
2244 return md5.hexdigest().lower()
2246 def compute_block_hash(data, algorithm):
2247 h = hashlib.new(algorithm)
2248 h.update(data.rstrip('\x00'))
2249 return h.hexdigest()
2251 def get_random_data(length=500):
2252 char_set = string.ascii_uppercase + string.digits
2253 return ''.join(random.choice(char_set) for x in xrange(length))
2256 MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2257 __D = r'(?P<day>\d{2})'
2258 __D2 = r'(?P<day>[ \d]\d)'
2259 __M = r'(?P<mon>\w{3})'
2260 __Y = r'(?P<year>\d{4})'
2261 __Y2 = r'(?P<year>\d{2})'
2262 __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2263 RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2264 RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2265 ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2266 for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2267 m = regex.match(date)
2272 o_names = ['kate.jpg',
2273 'kate_beckinsale.jpg',
2274 'How To Win Friends And Influence People.pdf',
2275 'moms_birthday.jpg',
2277 'Disturbed - Down With The Sickness.mp3',
2278 'army_of_darkness.avi',
2280 'photos/animals/dogs/poodle.jpg',
2281 'photos/animals/dogs/terrier.jpg',
2282 'photos/animals/cats/persian.jpg',
2283 'photos/animals/cats/siamese.jpg',
2284 'photos/plants/fern.jpg',
2285 'photos/plants/rose.jpg',
2290 if get_user() == 'test':
2291 unittest.main(module='pithos.tools.test')
2293 print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2296 if __name__ == "__main__":