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
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
379 def test_if_modified_since_invalid_date(self):
380 c = self.client.list_containers(if_modified_since='')
381 self.assertEqual(len(c), len(self.containers))
383 def test_if_not_modified_since(self):
384 now = datetime.datetime.utcnow()
385 since = now + datetime.timedelta(1)
387 for f in DATE_FORMATS:
388 args = {'if_modified_since':'%s' %since.strftime(f)}
391 self.assert_raises_fault(304, self.client.list_containers, **args)
393 def test_if_unmodified_since(self):
394 now = datetime.datetime.utcnow()
395 since = now + datetime.timedelta(1)
397 for f in DATE_FORMATS:
398 c = self.client.list_containers(if_unmodified_since=since.strftime(f))
401 self.assertEqual(self.containers, c)
403 def test_if_unmodified_since_precondition_failed(self):
404 t = datetime.datetime.utcnow()
405 t2 = t - datetime.timedelta(minutes=10)
408 self.client.create_container('dummy')
410 for f in DATE_FORMATS:
411 past = t2.strftime(f)
413 args = {'if_unmodified_since':'%s' %past}
415 #assert precondition failed
416 self.assert_raises_fault(412, self.client.list_containers, **args)
418 class AccountPost(BaseTestCase):
420 BaseTestCase.setUp(self)
421 self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
422 for item in self.containers:
423 self.client.create_container(item)
426 self.client.update_account_metadata(**meta)
427 self.updated_meta = self.initial_meta.update(meta)
429 def test_update_meta(self):
430 with AssertMappingInvariant(self.client.retrieve_account_groups):
431 meta = {'test':'test', 'tost':'tost'}
432 self.client.update_account_metadata(**meta)
434 meta.update(self.initial_meta)
435 self.assertEqual(meta,
436 self.client.retrieve_account_metadata(
439 def test_invalid_account_update_meta(self):
440 meta = {'test':'test', 'tost':'tost'}
441 self.assert_raises_fault(403,
442 self.invalid_client.update_account_metadata,
445 def test_reset_meta(self):
446 with AssertMappingInvariant(self.client.retrieve_account_groups):
447 meta = {'test':'test', 'tost':'tost'}
448 self.client.update_account_metadata(**meta)
450 meta = {'test':'test33'}
451 self.client.reset_account_metadata(**meta)
453 self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
455 def test_delete_meta(self):
456 with AssertMappingInvariant(self.client.retrieve_account_groups):
457 meta = {'test':'test', 'tost':'tost'}
458 self.client.update_account_metadata(**meta)
460 self.client.delete_account_metadata(meta.keys())
462 account_meta = self.client.retrieve_account_metadata(restricted=True)
464 self.assertTrue(m not in account_meta.keys())
466 def test_set_account_groups(self):
467 with AssertMappingInvariant(self.client.retrieve_account_metadata):
468 groups = {'pithosdev':'verigak,gtsouk,chazapis'}
469 self.client.set_account_groups(**groups)
471 self.assertEqual(set(groups['pithosdev']),
472 set(self.client.retrieve_account_groups()['pithosdev']))
474 more_groups = {'clientsdev':'pkanavos,mvasilak'}
475 self.client.set_account_groups(**more_groups)
477 groups.update(more_groups)
478 self.assertEqual(set(groups['clientsdev']),
479 set(self.client.retrieve_account_groups()['clientsdev']))
481 def test_reset_account_groups(self):
482 with AssertMappingInvariant(self.client.retrieve_account_metadata):
483 groups = {'pithosdev':'verigak,gtsouk,chazapis',
484 'clientsdev':'pkanavos,mvasilak'}
485 self.client.set_account_groups(**groups)
487 self.assertEqual(set(groups['pithosdev'].split(',')),
488 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
489 self.assertEqual(set(groups['clientsdev'].split(',')),
490 set(self.client.retrieve_account_groups()['clientsdev'].split(',')))
492 groups = {'pithosdev':'verigak,gtsouk,chazapis,papagian'}
493 self.client.reset_account_groups(**groups)
495 self.assertEqual(set(groups['pithosdev'].split(',')),
496 set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
498 def test_delete_account_groups(self):
499 with AssertMappingInvariant(self.client.retrieve_account_metadata):
500 groups = {'pithosdev':'verigak,gtsouk,chazapis',
501 'clientsdev':'pkanavos,mvasilak'}
502 self.client.set_account_groups(**groups)
504 self.client.unset_account_groups(groups.keys())
506 self.assertEqual({}, self.client.retrieve_account_groups())
508 class ContainerHead(BaseTestCase):
510 BaseTestCase.setUp(self)
511 self.container = 'apples'
512 self.client.create_container(self.container)
514 def test_get_meta(self):
515 meta = {'trash':'true'}
516 t1 = datetime.datetime.utcnow()
517 o = self.upload_random_data(self.container, o_names[0], **meta)
519 headers = self.client.retrieve_container_metadata(self.container)
520 self.assertEqual(headers['x-container-object-count'], '1')
521 self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
522 t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
524 threashold = datetime.timedelta(seconds=1)
525 self.assertTrue(delta < threashold)
526 self.assertTrue(headers['x-container-object-meta'])
527 self.assertTrue('Trash' in headers['x-container-object-meta'])
529 class ContainerGet(BaseTestCase):
531 BaseTestCase.setUp(self)
532 self.container = ['pears', 'apples']
533 for c in self.container:
534 self.client.create_container(c)
536 for o in o_names[:8]:
537 self.obj.append(self.upload_random_data(self.container[0], o))
538 for o in o_names[8:]:
539 self.obj.append(self.upload_random_data(self.container[1], o))
541 def test_list_objects(self):
542 objects = self.client.list_objects(self.container[0])
543 l = [elem['name'] for elem in self.obj[:8]]
545 self.assertEqual(objects, l)
547 def test_list_objects_containing_slash(self):
548 self.client.create_container('test')
549 self.upload_random_data('test', '/objectname')
551 objects = self.client.list_objects('test')
552 self.assertEqual(objects, ['/objectname'])
554 objects = self.client.list_objects('test', format='json')
555 self.assertEqual(objects[0]['name'], '/objectname')
557 objects = self.client.list_objects('test', format='xml')
558 self.assert_extended(objects, 'xml', 'object')
559 node_name = objects.getElementsByTagName('name')[0]
560 self.assertEqual(node_name.firstChild.data, '/objectname')
562 def test_list_objects_with_limit_marker(self):
563 objects = self.client.list_objects(self.container[0], limit=2)
564 l = [elem['name'] for elem in self.obj[:8]]
566 self.assertEqual(objects, l[:2])
568 markers = ['How To Win Friends And Influence People.pdf',
572 objects = self.client.list_objects(self.container[0], limit=limit,
574 l = [elem['name'] for elem in self.obj[:8]]
576 start = l.index(m) + 1
578 end = end if len(l) >= end else len(l)
579 self.assertEqual(objects, l[start:end])
582 def _test_list_limit_exceeds(self):
583 self.client.create_container('pithos')
585 for i in range(10001):
586 self.client.create_zero_length_object('pithos', i)
588 self.assertEqual(10000, len(self.client.list_objects('pithos')))
590 def test_list_empty_params(self):
591 objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
593 objects = objects.strip().split('\n')
594 self.assertEqual(objects,
595 self.client.list_objects(self.container[0]))
597 def test_list_pseudo_hierarchical_folders(self):
598 objects = self.client.list_objects(self.container[1], prefix='photos',
600 self.assertEquals(['photos/animals/', 'photos/me.jpg',
601 'photos/plants/'], objects)
603 objects = self.client.list_objects(self.container[1],
604 prefix='photos/animals',
606 l = ['photos/animals/cats/', 'photos/animals/dogs/']
607 self.assertEquals(l, objects)
609 objects = self.client.list_objects(self.container[1], path='photos')
610 self.assertEquals(['photos/me.jpg'], objects)
612 def test_extended_list_json(self):
613 objects = self.client.list_objects(self.container[1], format='json',
614 limit=2, prefix='photos/animals',
616 self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
617 self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
619 def test_extended_list_xml(self):
620 xml = self.client.list_objects(self.container[1], format='xml', limit=4,
621 prefix='photos', delimiter='/')
622 self.assert_extended(xml, 'xml', 'object', size=4)
623 dirs = xml.getElementsByTagName('subdir')
624 self.assertEqual(len(dirs), 2)
625 self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
626 self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
628 objects = xml.getElementsByTagName('name')
629 self.assertEqual(len(objects), 1)
630 self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
632 def test_list_meta_double_matching(self):
633 meta = {'quality':'aaa', 'stock':'true'}
634 self.client.update_object_metadata(self.container[0],
635 self.obj[0]['name'], **meta)
636 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
637 self.assertEqual(len(obj), 1)
638 self.assertTrue(obj, self.obj[0]['name'])
640 def test_list_using_meta(self):
641 meta = {'quality':'aaa'}
642 for o in self.obj[:2]:
643 self.client.update_object_metadata(self.container[0], o['name'],
645 meta = {'stock':'true'}
646 for o in self.obj[3:5]:
647 self.client.update_object_metadata(self.container[0], o['name'],
650 obj = self.client.list_objects(self.container[0], meta='Quality')
651 self.assertEqual(len(obj), 2)
652 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
654 # test case insensitive
655 obj = self.client.list_objects(self.container[0], meta='quality')
656 self.assertEqual(len(obj), 2)
657 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
659 # test multiple matches
660 obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
661 self.assertEqual(len(obj), 4)
662 self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
664 # test non 1-1 multiple match
665 obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
666 self.assertEqual(len(obj), 2)
667 self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
669 def test_if_modified_since(self):
670 t = datetime.datetime.utcnow()
671 t2 = t - datetime.timedelta(minutes=10)
674 self.upload_random_data(self.container[0], o_names[0])
676 for f in DATE_FORMATS:
677 past = t2.strftime(f)
679 o = self.client.list_objects(self.container[0],
680 if_modified_since=past)
682 self.client.list_objects(self.container[0]))
684 self.failIf(f.status == 304) #fail if not modified
686 def test_if_modified_since_invalid_date(self):
687 headers = {'if-modified-since':''}
688 o = self.client.list_objects(self.container[0], if_modified_since='')
689 self.assertEqual(o, self.client.list_objects(self.container[0]))
691 def test_if_not_modified_since(self):
692 now = datetime.datetime.utcnow()
693 since = now + datetime.timedelta(1)
695 for f in DATE_FORMATS:
696 args = {'if_modified_since':'%s' %since.strftime(f)}
699 self.assert_raises_fault(304, self.client.list_objects,
700 self.container[0], **args)
702 def test_if_unmodified_since(self):
703 now = datetime.datetime.utcnow()
704 since = now + datetime.timedelta(1)
706 for f in DATE_FORMATS:
707 obj = self.client.list_objects(self.container[0],
708 if_unmodified_since=since.strftime(f))
711 self.assertEqual(obj, self.client.list_objects(self.container[0]))
713 def test_if_unmodified_since_precondition_failed(self):
714 t = datetime.datetime.utcnow()
715 t2 = t - datetime.timedelta(minutes=10)
718 self.client.create_container('dummy')
720 for f in DATE_FORMATS:
721 past = t2.strftime(f)
723 args = {'if_unmodified_since':'%s' %past}
725 #assert precondition failed
726 self.assert_raises_fault(412, self.client.list_objects,
727 self.container[0], **args)
729 class ContainerPut(BaseTestCase):
731 BaseTestCase.setUp(self)
732 self.containers = ['c1', 'c2']
734 def test_create(self):
735 self.client.create_container(self.containers[0])
736 containers = self.client.list_containers()
737 self.assertTrue(self.containers[0] in containers)
738 self.assert_container_exists(self.containers[0])
740 def test_create_twice(self):
741 self.client.create_container(self.containers[0])
742 self.assertTrue(not self.client.create_container(self.containers[0]))
744 def test_quota(self):
745 self.client.create_container(self.containers[0])
747 policy = {'quota':100}
748 self.client.set_container_policies('c1', **policy)
750 meta = self.client.retrieve_container_metadata('c1')
751 self.assertTrue('x-container-policy-quota' in meta)
752 self.assertEqual(meta['x-container-policy-quota'], '100')
755 kwargs = {'length':101}
756 self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
760 self.client.set_container_policies('c1', **policy)
762 class ContainerPost(BaseTestCase):
764 BaseTestCase.setUp(self)
765 self.container = 'apples'
766 self.client.create_container(self.container)
768 def test_update_meta(self):
769 meta = {'test':'test33',
771 self.client.update_container_metadata(self.container, **meta)
772 headers = self.client.retrieve_container_metadata(self.container)
773 for k,v in meta.items():
774 k = 'x-container-meta-%s' % k
775 self.assertTrue(headers[k])
776 self.assertEqual(headers[k], v)
778 class ContainerDelete(BaseTestCase):
780 BaseTestCase.setUp(self)
781 self.containers = ['c1', 'c2']
782 for c in self.containers:
783 self.client.create_container(c)
785 def test_delete(self):
786 status = self.client.delete_container(self.containers[0])[0]
787 self.assertEqual(status, 204)
789 def test_delete_non_empty(self):
790 self.upload_random_data(self.containers[1], o_names[0])
791 self.assert_raises_fault(409, self.client.delete_container,
794 def test_delete_invalid(self):
795 self.assert_raises_fault(404, self.client.delete_container, 'c3')
797 class ObjectGet(BaseTestCase):
799 BaseTestCase.setUp(self)
800 self.containers = ['c1', 'c2']
801 #create some containers
802 for c in self.containers:
803 self.client.create_container(c)
806 names = ('obj1', 'obj2')
809 self.objects.append(self.upload_random_data(self.containers[1], n))
811 def test_versions(self):
812 c = self.containers[1]
814 b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
815 self.assert_versionlist_structure(b)
818 meta = {'quality':'AAA', 'stock':True}
819 self.client.update_object_metadata(c, o['name'], **meta)
821 a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
822 self.assert_versionlist_structure(a)
823 self.assertEqual(len(b)+1, len(a))
824 self.assertEqual(b, a[:-1])
826 #get exact previous version metadata
828 v_meta = self.client.retrieve_object_metadata(c, o['name'],
831 for k in meta.keys():
832 self.assertTrue(k not in v_meta)
835 data = get_random_data()
836 self.client.update_object(c, o['name'], StringIO(data))
838 aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
839 self.assert_versionlist_structure(aa)
840 self.assertEqual(len(a)+1, len(aa))
841 self.assertEqual(a, aa[:-1])
843 #get exact previous version
845 v_data = self.client.retrieve_object_version(c, o['name'], version=v)
846 self.assertEqual(o['data'], v_data)
847 self.assertEqual(self.client.retrieve_object(c, o['name']),
848 '%s%s' %(v_data, data))
852 o = self.client.retrieve_object(self.containers[1],
853 self.objects[0]['name'],
854 self.objects[0]['meta'])
855 self.assertEqual(o, self.objects[0]['data'])
857 def test_objects_with_trailing_spaces(self):
858 self.client.create_container('test')
860 self.upload_random_data('test', 'a')
861 #look for 'a ' object
862 self.assert_raises_fault(404, self.client.retrieve_object,
866 self.client.delete_object('test', 'a')
867 self.assert_raises_fault(404, self.client.retrieve_object,
871 self.upload_random_data('test', 'a ')
873 self.assert_raises_fault(404, self.client.retrieve_object,
876 def test_get_invalid(self):
877 self.assert_raises_fault(404, self.client.retrieve_object,
878 self.containers[0], self.objects[0]['name'])
880 def test_get_partial(self):
881 #perform get with range
882 status, headers, data = self.client.request_object(self.containers[1],
883 self.objects[0]['name'],
886 #assert successful partial content
887 self.assertEqual(status, 206)
890 self.assertEqual(headers['content-type'],
891 self.objects[0]['meta']['content_type'])
893 #assert content length
894 self.assertEqual(int(headers['content-length']), 500)
897 self.assertEqual(self.objects[0]['data'][:500], data)
899 def test_get_final_500(self):
900 #perform get with range
901 headers = {'range':'bytes=-500'}
902 status, headers, data = self.client.request_object(self.containers[1],
903 self.objects[0]['name'],
906 #assert successful partial content
907 self.assertEqual(status, 206)
910 self.assertEqual(headers['content-type'],
911 self.objects[0]['meta']['content_type'])
913 #assert content length
914 self.assertEqual(int(headers['content-length']), 500)
917 self.assertTrue(self.objects[0]['data'][-500:], data)
919 def test_get_rest(self):
920 #perform get with range
921 offset = len(self.objects[0]['data']) - 500
922 status, headers, data = self.client.request_object(self.containers[1],
923 self.objects[0]['name'],
924 range='bytes=%s-' %offset)
926 #assert successful partial content
927 self.assertEqual(status, 206)
930 self.assertEqual(headers['content-type'],
931 self.objects[0]['meta']['content_type'])
933 #assert content length
934 self.assertEqual(int(headers['content-length']), 500)
937 self.assertTrue(self.objects[0]['data'][-500:], data)
939 def test_get_range_not_satisfiable(self):
940 #perform get with range
941 offset = len(self.objects[0]['data']) + 1
943 #assert range not satisfiable
944 self.assert_raises_fault(416, self.client.retrieve_object,
945 self.containers[1], self.objects[0]['name'],
946 range='bytes=0-%s' %offset)
948 def test_multiple_range(self):
949 #perform get with multiple range
950 ranges = ['0-499', '-500', '1000-']
951 bytes = 'bytes=%s' % ','.join(ranges)
952 status, headers, data = self.client.request_object(self.containers[1],
953 self.objects[0]['name'],
956 # assert partial content
957 self.assertEqual(status, 206)
959 # assert Content-Type of the reply will be multipart/byteranges
960 self.assertTrue(headers['content-type'])
961 content_type_parts = headers['content-type'].split()
962 self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
964 boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
965 cparts = data.split(boundary)[1:-1]
967 # assert content parts are exactly 2
968 self.assertEqual(len(cparts), len(ranges))
970 # for each content part assert headers
973 content = cpart.split('\r\n')
974 headers = content[1:3]
975 content_range = headers[0].split(': ')
976 self.assertEqual(content_range[0], 'Content-Range')
978 r = ranges[i].split('-')
979 if not r[0] and not r[1]:
982 start = len(self.objects[0]['data']) - int(r[1])
983 end = len(self.objects[0]['data'])
986 end = len(self.objects[0]['data'])
990 fdata = self.objects[0]['data'][start:end]
991 sdata = '\r\n'.join(content[4:-1])
992 self.assertEqual(len(fdata), len(sdata))
993 self.assertEquals(fdata, sdata)
996 def test_multiple_range_not_satisfiable(self):
997 #perform get with multiple range
998 out_of_range = len(self.objects[0]['data']) + 1
999 ranges = ['0-499', '-500', '%d-' %out_of_range]
1000 bytes = 'bytes=%s' % ','.join(ranges)
1002 # assert partial content
1003 self.assert_raises_fault(416, self.client.retrieve_object,
1005 self.objects[0]['name'], range=bytes)
1007 def test_get_with_if_match(self):
1008 #perform get with If-Match
1009 etag = self.objects[0]['hash']
1010 status, headers, data = self.client.request_object(self.containers[1],
1011 self.objects[0]['name'],
1014 self.assertEqual(status, 200)
1016 #assert content-type
1017 self.assertEqual(headers['content-type'],
1018 self.objects[0]['meta']['content_type'])
1020 #assert response content
1021 self.assertEqual(self.objects[0]['data'], data)
1023 def test_get_with_if_match_star(self):
1024 #perform get with If-Match *
1025 headers = {'if-match':'*'}
1026 status, headers, data = self.client.request_object(self.containers[1],
1027 self.objects[0]['name'],
1030 self.assertEqual(status, 200)
1032 #assert content-type
1033 self.assertEqual(headers['content-type'],
1034 self.objects[0]['meta']['content_type'])
1036 #assert response content
1037 self.assertEqual(self.objects[0]['data'], data)
1039 def test_get_with_multiple_if_match(self):
1040 #perform get with If-Match
1041 etags = [i['hash'] for i in self.objects if i]
1042 etags = ','.join('"%s"' % etag for etag in etags)
1043 status, headers, data = self.client.request_object(self.containers[1],
1044 self.objects[0]['name'],
1047 self.assertEqual(status, 200)
1049 #assert content-type
1050 self.assertEqual(headers['content-type'],
1051 self.objects[0]['meta']['content_type'])
1053 #assert content-type
1054 self.assertEqual(headers['content-type'],
1055 self.objects[0]['meta']['content_type'])
1057 #assert response content
1058 self.assertEqual(self.objects[0]['data'], data)
1060 def test_if_match_precondition_failed(self):
1061 #assert precondition failed
1062 self.assert_raises_fault(412, self.client.retrieve_object,
1064 self.objects[0]['name'], if_match='123')
1066 def test_if_none_match(self):
1067 #perform get with If-None-Match
1068 status, headers, data = self.client.request_object(self.containers[1],
1069 self.objects[0]['name'],
1070 if_none_match='123')
1073 self.assertEqual(status, 200)
1075 #assert content-type
1076 self.assertEqual(headers['content_type'],
1077 self.objects[0]['meta']['content_type'])
1079 def test_if_none_match(self):
1080 #perform get with If-None-Match * and assert not modified
1081 self.assert_raises_fault(304, self.client.retrieve_object,
1083 self.objects[0]['name'],
1086 def test_if_none_match_not_modified(self):
1087 #perform get with If-None-Match and assert not modified
1088 self.assert_raises_fault(304, self.client.retrieve_object,
1090 self.objects[0]['name'],
1091 if_none_match=self.objects[0]['hash'])
1093 meta = self.client.retrieve_object_metadata(self.containers[1],
1094 self.objects[0]['name'])
1095 self.assertEqual(meta['etag'], self.objects[0]['hash'])
1097 def test_if_modified_since(self):
1098 t = datetime.datetime.utcnow()
1099 t2 = t - datetime.timedelta(minutes=10)
1102 self.upload_data(self.containers[1],
1103 self.objects[0]['name'],
1104 self.objects[0]['data'][:200])
1106 for f in DATE_FORMATS:
1107 past = t2.strftime(f)
1109 headers = {'if-modified-since':'%s' %past}
1111 o = self.client.retrieve_object(self.containers[1],
1112 self.objects[0]['name'],
1113 if_modified_since=past)
1115 self.client.retrieve_object(self.containers[1],
1116 self.objects[0]['name']))
1118 self.failIf(f.status == 304)
1120 def test_if_modified_since_invalid_date(self):
1121 o = self.client.retrieve_object(self.containers[1],
1122 self.objects[0]['name'],
1123 if_modified_since='')
1124 self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1125 self.objects[0]['name']))
1127 def test_if_not_modified_since(self):
1128 now = datetime.datetime.utcnow()
1129 since = now + datetime.timedelta(1)
1131 for f in DATE_FORMATS:
1132 #assert not modified
1133 self.assert_raises_fault(304, self.client.retrieve_object,
1134 self.containers[1], self.objects[0]['name'],
1135 if_modified_since=since.strftime(f))
1137 def test_if_unmodified_since(self):
1138 now = datetime.datetime.utcnow()
1139 since = now + datetime.timedelta(1)
1141 for f in DATE_FORMATS:
1142 t = since.strftime(f)
1143 status, headers, data = self.client.request_object(self.containers[1],
1144 self.objects[0]['name'],
1145 if_unmodified_since=t)
1147 self.assertEqual(status, 200)
1148 self.assertEqual(self.objects[0]['data'], data)
1150 #assert content-type
1151 self.assertEqual(headers['content-type'],
1152 self.objects[0]['meta']['content_type'])
1154 def test_if_unmodified_since_precondition_failed(self):
1155 t = datetime.datetime.utcnow()
1156 t2 = t - datetime.timedelta(minutes=10)
1159 self.upload_data(self.containers[1],
1160 self.objects[0]['name'],
1161 self.objects[0]['data'][:200])
1163 for f in DATE_FORMATS:
1164 past = t2.strftime(f)
1165 #assert precondition failed
1166 self.assert_raises_fault(412, self.client.retrieve_object,
1167 self.containers[1], self.objects[0]['name'],
1168 if_unmodified_since=past)
1170 def test_hashes(self):
1173 o = self.upload_random_data(self.containers[1], fname, l)
1175 body = self.client.retrieve_object(self.containers[1], fname,
1177 hashes = body['hashes']
1178 block_size = body['block_size']
1179 block_hash = body['block_hash']
1180 block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1181 self.assertTrue(len(hashes), block_num)
1184 start = i * block_size
1185 end = (i + 1) * block_size
1186 hash = compute_block_hash(o['data'][start:end], block_hash)
1187 self.assertEqual(h, hash)
1190 class ObjectPut(BaseTestCase):
1192 BaseTestCase.setUp(self)
1193 self.container = 'c1'
1194 self.client.create_container(self.container)
1196 def test_upload(self):
1198 meta = {'test':'test1'}
1199 o = self.upload_random_data(self.container, name, **meta)
1201 headers = self.client.retrieve_object_metadata(self.container,
1204 self.assertTrue('test' in headers.keys())
1205 self.assertEqual(headers['test'], meta['test'])
1207 #assert uploaded content
1208 status, h, data = self.client.request_object(self.container, name)
1209 self.assertEqual(len(o['data']), int(h['content-length']))
1210 self.assertEqual(o['data'], data)
1212 #assert content-type
1213 self.assertEqual(h['content-type'], o['meta']['content_type'])
1215 def _test_maximum_upload_size_exceeds(self):
1217 meta = {'test':'test1'}
1219 length=1024*1024*100
1220 self.assert_raises_fault(400, self.upload_random_data, self.container,
1221 name, length, **meta)
1223 def test_upload_with_name_containing_slash(self):
1224 name = '/%s' % o_names[0]
1225 meta = {'test':'test1'}
1226 o = self.upload_random_data(self.container, name, **meta)
1228 self.assertEqual(o['data'],
1229 self.client.retrieve_object(self.container, name))
1231 self.assertTrue(name in self.client.list_objects(self.container))
1233 def test_create_directory_marker(self):
1234 self.client.create_directory_marker(self.container, 'foo')
1235 meta = self.client.retrieve_object_metadata(self.container, 'foo')
1236 self.assertEqual(meta['content-length'], '0')
1237 self.assertEqual(meta['content-type'], 'application/directory')
1239 def test_upload_unprocessable_entity(self):
1240 meta={'etag':'123', 'test':'test1'}
1242 #assert unprocessable entity
1243 self.assert_raises_fault(422, self.upload_random_data, self.container,
1246 def test_chunked_transfer(self):
1247 data = get_random_data()
1249 self.client.create_object_using_chunks(self.container, objname,
1252 uploaded_data = self.client.retrieve_object(self.container, objname)
1253 self.assertEqual(data, uploaded_data)
1255 def test_manifestation(self):
1256 prefix = 'myobject/'
1259 part = '%s%d' %(prefix, i)
1260 o = self.upload_random_data(self.container, part)
1263 manifest = '%s/%s' %(self.container, prefix)
1264 self.client.create_manifestation(self.container, 'large-object', manifest)
1266 self.assert_object_exists(self.container, 'large-object')
1267 self.assertEqual(data, self.client.retrieve_object(self.container,
1270 r = self.client.retrieve_object_hashmap(self.container,'large-object')
1271 hashes = r['hashes']
1272 block_size = int(r['block_size'])
1273 block_hash = r['block_hash']
1275 block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1276 self.assertEqual(block_num, len(hashes))
1278 #wrong manifestation
1279 self.client.create_manifestation(self.container, 'large-object',
1280 '%s/invalid' % self.container)
1281 self.assertEqual('', self.client.retrieve_object(self.container,
1284 def test_create_zero_length_object(self):
1287 zero = self.client.create_zero_length_object(c, o)
1288 zero_meta = self.client.retrieve_object_metadata(c, o)
1289 zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1290 zero_data = self.client.retrieve_object(c, o)
1292 self.assertEqual(int(zero_meta['content-length']), 0)
1293 hasher = newhasher('sha256')
1295 emptyhash = hasher.digest()
1296 self.assertEqual(zero_hash, [hexlify(emptyhash)])
1297 self.assertEqual(zero_data, '')
1299 def test_create_object_by_hashmap(self):
1302 self.upload_random_data(c, o)
1303 hashmap = self.client.retrieve_object(c, o, format='json')
1305 self.client.create_object_by_hashmap(c, o2, hashmap)
1306 self.assertEqual(self.client.retrieve_object(c, o),
1307 self.client.retrieve_object(c, o))
1309 class ObjectCopy(BaseTestCase):
1311 BaseTestCase.setUp(self)
1312 self.containers = ['c1', 'c2']
1313 for c in self.containers:
1314 self.client.create_container(c)
1315 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1317 def test_copy(self):
1318 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1319 self.containers[0], self.obj['name']):
1321 meta = {'test':'testcopy'}
1322 status = self.client.copy_object(self.containers[0],
1328 #assert copy success
1329 self.assertEqual(status, 201)
1331 #assert access the new object
1332 headers = self.client.retrieve_object_metadata(self.containers[0],
1334 self.assertTrue('x-object-meta-test' in headers.keys())
1335 self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1337 #assert etag is the same
1338 self.assertEqual(headers['etag'], self.obj['hash'])
1340 #assert src object still exists
1341 self.assert_object_exists(self.containers[0], self.obj['name'])
1343 def test_copy_from_different_container(self):
1344 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1345 self.containers[0], self.obj['name']):
1346 meta = {'test':'testcopy'}
1347 status = self.client.copy_object(self.containers[0],
1352 self.assertEqual(status, 201)
1354 # assert updated metadata
1355 meta = self.client.retrieve_object_metadata(self.containers[1],
1358 self.assertTrue('test' in meta.keys())
1359 self.assertTrue(meta['test'], 'testcopy')
1361 #assert src object still exists
1362 self.assert_object_exists(self.containers[0], self.obj['name'])
1364 def test_copy_invalid(self):
1365 #copy from invalid object
1366 meta = {'test':'testcopy'}
1367 self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1368 'test.py', self.containers[1], 'testcopy', meta)
1370 #copy from invalid container
1371 meta = {'test':'testcopy'}
1372 self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1373 self.obj['name'], self.containers[1],
1376 class ObjectMove(BaseTestCase):
1378 BaseTestCase.setUp(self)
1379 self.containers = ['c1', 'c2']
1380 for c in self.containers:
1381 self.client.create_container(c)
1382 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1384 def test_move(self):
1385 meta = self.client.retrieve_object_metadata(self.containers[0],
1387 self.assertTrue('x-object-uuid' in meta)
1388 uuid = meta['x-object-uuid']
1391 meta = {'test':'testcopy'}
1392 src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1393 status = self.client.move_object(self.containers[0], self.obj['name'],
1394 self.containers[0], 'testcopy',
1397 #assert successful move
1398 self.assertEqual(status, 201)
1400 #assert updated metadata
1401 meta = self.client.retrieve_object_metadata(self.containers[0],
1403 self.assertTrue('x-object-meta-test' in meta.keys())
1404 self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1407 self.assertTrue(meta['x-object-uuid'], uuid)
1409 #assert src object no more exists
1410 self.assert_object_not_exists(self.containers[0], self.obj['name'])
1412 class ObjectPost(BaseTestCase):
1414 BaseTestCase.setUp(self)
1415 self.containers = ['c1', 'c2']
1416 for c in self.containers:
1417 self.client.create_container(c)
1420 self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1422 def test_update_meta(self):
1423 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1425 self.obj[0]['name']):
1426 #perform update metadata
1427 more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1428 status = self.client.update_object_metadata(self.containers[0],
1429 self.obj[0]['name'],
1431 #assert request accepted
1432 self.assertEqual(status, 202)
1434 #assert old metadata are still there
1435 headers = self.client.retrieve_object_metadata(self.containers[0],
1436 self.obj[0]['name'],
1438 #assert new metadata have been updated
1439 for k,v in more.items():
1440 self.assertTrue(k in headers.keys())
1441 self.assertTrue(headers[k], v)
1444 more = {'f' * 114: 'b' * 257}
1445 self.assert_raises_fault(400, self.client.update_object_metadata,
1447 self.obj[0]['name'],
1450 #perform update metadata
1451 more = {'α': 'β' * 256}
1452 status = self.client.update_object_metadata(self.containers[0],
1453 self.obj[0]['name'],
1455 #assert request accepted
1456 self.assertEqual(status, 202)
1458 #assert old metadata are still there
1459 headers = self.client.retrieve_object_metadata(self.containers[0],
1460 self.obj[0]['name'],
1462 #assert new metadata have been updated
1463 for k,v in more.items():
1464 self.assertTrue(k in headers.keys())
1465 self.assertTrue(headers[k], v)
1468 more = {'α': 'β' * 257}
1469 self.assert_raises_fault(400, self.client.update_object_metadata,
1471 self.obj[0]['name'],
1474 def test_update_object(self,
1477 instance_length = True,
1478 content_length = 500):
1479 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1481 self.obj[0]['name']):
1482 l = len(self.obj[0]['data'])
1483 range = 'bytes %d-%d/%s' %(first_byte_pos,
1485 l if instance_length else '*')
1486 partial = last_byte_pos - first_byte_pos + 1
1487 length = first_byte_pos + partial
1488 data = get_random_data(partial)
1489 args = {'content_type':'application/octet-stream',
1490 'content_range':'%s' %range}
1492 args['content_length'] = content_length
1494 r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1495 StringIO(data), **args)
1498 if partial < 0 or (instance_length and l <= last_byte_pos):
1499 self.assertEqual(status, 202)
1501 self.assertEqual(status, 204)
1502 #check modified object
1503 content = self.client.retrieve_object(self.containers[0],
1504 self.obj[0]['name'])
1505 self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1506 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1507 self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1508 self.assertEqual(etag, compute_md5_hash(content))
1510 def test_update_object_lt_blocksize(self):
1511 self.test_update_object(10, 20, content_length=None)
1513 def test_update_object_gt_blocksize(self):
1514 o = self.upload_random_data(self.containers[0], o_names[1],
1515 length=4*1024*1024+5)
1516 c = self.containers[0]
1519 first_byte_pos = 4*1024*1024+1
1520 last_byte_pos = 4*1024*1024+4
1521 l = last_byte_pos - first_byte_pos + 1
1522 data = get_random_data(l)
1523 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1524 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1525 content = self.client.retrieve_object(c, o_name)
1526 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1527 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1528 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1530 def test_update_object_divided_by_blocksize(self):
1531 o = self.upload_random_data(self.containers[0], o_names[1],
1532 length=4*1024*1024+5)
1533 c = self.containers[0]
1536 first_byte_pos = 4*1024*1024
1537 last_byte_pos = 5*1024*1024
1538 l = last_byte_pos - first_byte_pos + 1
1539 data = get_random_data(l)
1540 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1541 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1542 content = self.client.retrieve_object(c, o_name)
1543 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1544 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1545 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1547 def test_update_object_no_content_length(self):
1548 self.test_update_object(content_length = None)
1550 def test_update_object_invalid_content_length(self):
1551 with AssertContentInvariant(self.client.retrieve_object,
1552 self.containers[0], self.obj[0]['name']):
1553 self.assert_raises_fault(400, self.test_update_object,
1554 content_length = 1000)
1556 def _test_update_object_invalid_range(self):
1557 with AssertContentInvariant(self.client.retrieve_object,
1558 self.containers[0], self.obj[0]['name']):
1559 self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1561 def _test_update_object_invalid_range_and_length(self):
1562 with AssertContentInvariant(self.client.retrieve_object,
1563 self.containers[0], self.obj[0]['name']):
1564 self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1567 def test_update_object_invalid_range_with_no_content_length(self):
1568 with AssertContentInvariant(self.client.retrieve_object,
1569 self.containers[0], self.obj[0]['name']):
1570 self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1571 content_length = None)
1573 def test_update_object_out_of_limits(self):
1574 with AssertContentInvariant(self.client.retrieve_object,
1575 self.containers[0], self.obj[0]['name']):
1576 l = len(self.obj[0]['data'])
1577 self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1579 def test_append(self):
1580 data = get_random_data(500)
1582 self.client.update_object(self.containers[0], self.obj[0]['name'],
1583 StringIO(data), content_length=500,
1584 content_type='application/octet-stream')
1586 content = self.client.retrieve_object(self.containers[0],
1587 self.obj[0]['name'])
1588 self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1589 self.assertEqual(content[:-500], self.obj[0]['data'])
1591 def test_update_with_chunked_transfer(self):
1592 data = get_random_data(500)
1594 fl = len(self.obj[0]['data'])
1596 self.client.update_object_using_chunks(self.containers[0],
1597 self.obj[0]['name'],
1600 content_type='application/octet-stream')
1602 #check modified object
1603 content = self.client.retrieve_object(self.containers[0],
1604 self.obj[0]['name'])
1605 self.assertEqual(content[0:dl], data)
1606 self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1608 def test_update_from_other_object(self):
1609 c = self.containers[0]
1613 source_data = self.client.retrieve_object(c, src)
1614 source_meta = self.client.retrieve_object_metadata(c, src)
1615 source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1617 #update zero length object
1618 self.client.create_zero_length_object(c, dest)
1619 source_object = '/%s/%s' % (c, src)
1620 self.client.update_from_other_source(c, dest, source_object)
1621 dest_data = self.client.retrieve_object(c, src)
1622 dest_meta = self.client.retrieve_object_metadata(c, dest)
1623 dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1624 self.assertEqual(source_data, dest_data)
1625 self.assertEqual(source_hash, dest_hash)
1628 self.client.update_from_other_source(c, dest, source_object)
1629 content = self.client.retrieve_object(c, dest)
1630 self.assertEqual(source_data * 2, content)
1632 def test_update_range_from_other_object(self):
1633 c = self.containers[0]
1637 src = self.obj[1]['name']
1638 src_data = self.client.retrieve_object(c, src)
1640 #update zero length object
1641 prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1642 source_object = '/%s/%s' % (c, src)
1643 first_byte_pos = 4*1024*1024+1
1644 last_byte_pos = 4*1024*1024+4
1645 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1646 self.client.update_from_other_source(c, dest, source_object,
1647 content_range=range)
1648 content = self.client.retrieve_object(c, dest)
1649 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1650 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1651 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1653 def test_update_hashes_from_other_object(self):
1654 c = self.containers[0]
1658 src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1660 #update zero length object
1661 prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1662 source_object = '/%s/%s' % (c, o_names[0])
1663 first_byte_pos = 4*1024*1024
1664 last_byte_pos = 5*1024*1024
1665 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1666 self.client.update_from_other_source(c, dest, source_object,
1667 content_range=range)
1668 content = self.client.retrieve_object(c, dest)
1669 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1670 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1671 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1674 def test_update_zero_length_object(self):
1675 c = self.containers[0]
1678 zero = self.client.create_zero_length_object(c, o)
1680 data = get_random_data()
1681 self.client.update_object(c, o, StringIO(data))
1682 self.client.create_object(c, other, StringIO(data))
1684 self.assertEqual(self.client.retrieve_object(c, o),
1685 self.client.retrieve_object(c, other))
1687 self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1688 self.client.retrieve_object_hashmap(c, other)["hashes"])
1690 class ObjectDelete(BaseTestCase):
1692 BaseTestCase.setUp(self)
1693 self.containers = ['c1', 'c2']
1694 for c in self.containers:
1695 self.client.create_container(c)
1696 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1698 def test_delete(self):
1699 #perform delete object
1700 self.client.delete_object(self.containers[0], self.obj['name'])[0]
1702 def test_delete_invalid(self):
1703 #assert item not found
1704 self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1707 class ListSharing(BaseTestCase):
1709 BaseTestCase.setUp(self)
1711 self.client.create_container('c%s' %i)
1712 self.client.create_container('c')
1714 self.upload_random_data('c1', 'o%s' %i)
1715 accounts = OTHER_ACCOUNTS.copy()
1716 self.o1_sharing_with = accounts.popitem()
1717 self.o1_sharing = [self.o1_sharing_with[1]]
1718 self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1722 l.append(accounts.popitem())
1724 def test_list_other_shared(self):
1725 self.other = Pithos_Client(get_url(),
1726 self.o1_sharing_with[0],
1727 self.o1_sharing_with[1])
1728 self.assertTrue(get_user() in self.other.list_shared_by_others())
1730 def test_list_my_shared(self):
1731 my_shared_containers = self.client.list_containers(shared=True)
1732 self.assertTrue('c1' in my_shared_containers)
1733 self.assertTrue('c2' not in my_shared_containers)
1735 my_shared_objects = self.client.list_objects('c1', shared=True)
1736 self.assertTrue('o1' in my_shared_objects)
1737 self.assertTrue('o2' not in my_shared_objects)
1739 class TestGreek(BaseTestCase):
1740 def test_create_container(self):
1741 self.client.create_container('φάκελος')
1742 self.assert_container_exists('φάκελος')
1744 self.assertTrue('φάκελος' in self.client.list_containers())
1746 def test_create_object(self):
1747 self.client.create_container('φάκελος')
1748 self.upload_random_data('φάκελος', 'αντικείμενο')
1750 self.assert_object_exists('φάκελος', 'αντικείμενο')
1751 self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1753 def test_copy_object(self):
1754 src_container = 'φάκελος'
1755 src_object = 'αντικείμενο'
1756 dest_container = 'αντίγραφα'
1757 dest_object = 'ασφαλές-αντίγραφο'
1759 self.client.create_container(src_container)
1760 self.upload_random_data(src_container, src_object)
1762 self.client.create_container(dest_container)
1763 self.client.copy_object(src_container, src_object, dest_container,
1766 self.assert_object_exists(src_container, src_object)
1767 self.assert_object_exists(dest_container, dest_object)
1768 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1770 def test_move_object(self):
1771 src_container = 'φάκελος'
1772 src_object = 'αντικείμενο'
1773 dest_container = 'αντίγραφα'
1774 dest_object = 'ασφαλές-αντίγραφο'
1776 self.client.create_container(src_container)
1777 self.upload_random_data(src_container, src_object)
1779 self.client.create_container(dest_container)
1780 self.client.move_object(src_container, src_object, dest_container,
1783 self.assert_object_not_exists(src_container, src_object)
1784 self.assert_object_exists(dest_container, dest_object)
1785 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1787 def test_delete_object(self):
1788 self.client.create_container('φάκελος')
1789 self.upload_random_data('φάκελος', 'αντικείμενο')
1790 self.assert_object_exists('φάκελος', 'αντικείμενο')
1792 self.client.delete_object('φάκελος', 'αντικείμενο')
1793 self.assert_object_not_exists('φάκελος', 'αντικείμενο')
1794 self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
1796 def test_delete_container(self):
1797 self.client.create_container('φάκελος')
1798 self.assert_container_exists('φάκελος')
1800 self.client.delete_container('φάκελος')
1801 self.assert_container_not_exists('φάκελος')
1802 self.assertTrue('φάκελος' not in self.client.list_containers())
1804 def test_account_meta(self):
1805 meta = {'ποιότητα':'ΑΑΑ'}
1806 self.client.update_account_metadata(**meta)
1807 meta = self.client.retrieve_account_metadata(restricted=True)
1808 self.assertTrue('ποιότητα' in meta.keys())
1809 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1811 def test_container_meta(self):
1812 meta = {'ποιότητα':'ΑΑΑ'}
1813 self.client.create_container('φάκελος', meta=meta)
1815 meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
1816 self.assertTrue('ποιότητα' in meta.keys())
1817 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1819 def test_object_meta(self):
1820 self.client.create_container('φάκελος')
1821 meta = {'ποιότητα':'ΑΑΑ'}
1822 self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
1824 meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
1826 self.assertTrue('ποιότητα' in meta.keys())
1827 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1829 def test_list_meta_filtering(self):
1830 self.client.create_container('φάκελος')
1831 meta = {'ποιότητα':'ΑΑΑ'}
1832 self.upload_random_data('φάκελος', 'ο1', **meta)
1833 self.upload_random_data('φάκελος', 'ο2')
1834 self.upload_random_data('φάκελος', 'ο3')
1836 meta = {'ποσότητα':'μεγάλη'}
1837 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1838 objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
1839 self.assertEquals(objects, ['ο1', 'ο2'])
1841 objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
1842 self.assertEquals(objects, ['ο2', 'ο3'])
1844 objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
1845 self.assertEquals(objects, ['ο3'])
1847 meta = {'ποιότητα':'ΑΒ'}
1848 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1849 objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
1850 self.assertEquals(objects, ['ο1'])
1851 objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
1852 self.assertEquals(objects, ['ο2'])
1854 meta = {'έτος':'2011'}
1855 self.client.update_object_metadata('φάκελος', 'ο3', **meta)
1856 meta = {'έτος':'2012'}
1857 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1858 objects = self.client.list_objects('φάκελος', meta='έτος<2012')
1859 self.assertEquals(objects, ['ο3'])
1860 objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
1861 self.assertEquals(objects, ['ο2', 'ο3'])
1862 objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
1863 self.assertEquals(objects, '')
1865 def test_groups(self):
1867 groups = {'σεφς':'chazapis,διογένης'}
1868 self.client.set_account_groups(**groups)
1869 groups.update(self.initial_groups)
1870 self.assertEqual(groups['σεφς'],
1871 self.client.retrieve_account_groups()['σεφς'])
1874 self.client.create_container('φάκελος')
1875 o = self.upload_random_data('φάκελος', 'ο1')
1876 self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
1877 chef = Pithos_Client(get_url(),
1880 self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
1881 'φάκελος', 'ο1', account=get_user())
1884 self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
1885 new_data = get_random_data()
1886 self.assert_not_raises_fault(403, chef.update_object,
1887 'φάκελος', 'ο1', StringIO(new_data),
1890 server_data = self.client.retrieve_object('φάκελος', 'ο1')
1891 self.assertEqual(server_data[:len(o['data'])], o['data'])
1892 self.assertEqual(server_data[len(o['data']):], new_data)
1894 def test_manifestation(self):
1895 self.client.create_container('κουβάς')
1899 part = '%s%d' %(prefix, i)
1900 o = self.upload_random_data('κουβάς', part)
1903 self.client.create_container('φάκελος')
1904 manifest = '%s/%s' %('κουβάς', prefix)
1905 self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
1907 self.assert_object_exists('φάκελος', 'άπαντα')
1908 self.assertEqual(data, self.client.retrieve_object('φάκελος',
1911 #wrong manifestation
1912 self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
1913 self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
1915 def test_update_from_another_object(self):
1916 self.client.create_container('κουβάς')
1917 src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
1918 initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
1919 source_object = '/%s/%s' % ('κουβάς', 'πηγή')
1920 self.client.update_from_other_source('κουβάς', 'νέο', source_object)
1923 self.client.retrieve_object('κουβάς', 'νέο'),
1924 '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
1926 class TestPermissions(BaseTestCase):
1928 BaseTestCase.setUp(self)
1931 self.authorized = ['chazapis', 'verigak', 'gtsouk']
1932 groups = {'pithosdev':','.join(self.authorized)}
1933 self.client.set_account_groups(**groups)
1935 self.container = 'c'
1937 self.client.create_container(self.container)
1938 self.upload_random_data(self.container, self.object)
1939 self.upload_random_data(self.container, self.object+'/')
1940 self.upload_random_data(self.container, self.object+'/a')
1941 self.upload_random_data(self.container, self.object+'a')
1942 self.upload_random_data(self.container, self.object+'a/')
1943 self.dir_content_types = ('application/directory', 'application/folder')
1945 def assert_read(self, authorized=[], any=False, depth=0):
1946 for token, account in OTHER_ACCOUNTS.items():
1947 cl = Pithos_Client(get_url(), token, account)
1948 if account in authorized or any:
1949 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
1950 self.container, self.object,
1953 self.assert_raises_fault(403, cl.retrieve_object_metadata,
1954 self.container, self.object,
1958 meta = self.client.retrieve_object_metadata(self.container, self.object)
1959 type = meta['content-type']
1960 derivatives = self.client.list_objects(self.container, prefix=self.object)
1961 #exclude the self.object
1962 del derivatives[derivatives.index(self.object)]
1963 for o in derivatives:
1964 for token, account in OTHER_ACCOUNTS.items():
1965 cl = Pithos_Client(get_url(), token, account)
1966 prefix = self.object if self.object.endswith('/') else self.object+'/'
1967 if (account in authorized or any) and \
1968 (type in self.dir_content_types) and \
1969 o.startswith(prefix):
1970 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
1971 self.container, o, account=get_user())
1973 self.assert_raises_fault(403, cl.retrieve_object_metadata,
1974 self.container, o, account=get_user())
1976 def assert_write(self, authorized=[], any=False):
1977 o_data = self.client.retrieve_object(self.container, self.object)
1978 for token, account in OTHER_ACCOUNTS.items():
1979 cl = Pithos_Client(get_url(), token, account)
1980 new_data = get_random_data()
1981 if account in authorized or any:
1983 self.assert_not_raises_fault(403, cl.update_object,
1984 self.container, self.object, StringIO(new_data),
1988 server_data = cl.retrieve_object(self.container, self.object, account=get_user())
1989 self.assertEqual(o_data, server_data[:len(o_data)])
1990 self.assertEqual(new_data, server_data[len(o_data):])
1991 o_data = server_data
1993 self.failIf(f.status == 403)
1995 self.assert_raises_fault(403, cl.update_object,
1996 self.container, self.object, StringIO(new_data),
1999 meta = self.client.retrieve_object_metadata(self.container, self.object)
2000 type = meta['content-type']
2001 derivatives = self.client.list_objects(self.container, prefix=self.object)
2003 del derivatives[derivatives.index(self.object)]
2004 for o in derivatives:
2005 for token, account in OTHER_ACCOUNTS.items():
2006 prefix = self.object if self.object.endswith('/') else self.object+'/'
2007 cl = Pithos_Client(get_url(), token, account)
2008 new_data = get_random_data()
2009 if (account in authorized or any) and \
2010 (type in self.dir_content_types) and \
2011 o.startswith(prefix):
2013 self.assert_not_raises_fault(403, cl.update_object,
2018 server_data = cl.retrieve_object(self.container, o, account=get_user())
2019 self.assertEqual(new_data, server_data[-len(new_data):])
2021 self.failIf(f.status == 403)
2023 self.assert_raises_fault(403, cl.update_object,
2028 def test_group_read(self):
2029 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2030 self.assert_read(authorized=self.authorized)
2032 def test_read_many(self):
2033 self.client.share_object(self.container, self.object, self.authorized)
2034 self.assert_read(authorized=self.authorized)
2036 def test_read_by_everyone(self):
2037 self.client.share_object(self.container, self.object, ['*'])
2038 self.assert_read(any=True)
2040 def test_read_directory(self):
2041 for type in self.dir_content_types:
2042 #change content type
2043 self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2044 self.client.share_object(self.container, self.object, ['*'])
2045 self.assert_read(any=True)
2046 self.client.share_object(self.container, self.object, self.authorized)
2047 self.assert_read(authorized=self.authorized)
2048 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2049 self.assert_read(authorized=self.authorized)
2051 def test_group_write(self):
2052 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2053 self.assert_write(authorized=self.authorized)
2055 def test_write_many(self):
2056 self.client.share_object(self.container, self.object, self.authorized, read=False)
2057 self.assert_write(authorized=self.authorized)
2059 def test_write_by_everyone(self):
2060 self.client.share_object(self.container, self.object, ['*'], read=False)
2061 self.assert_write(any=True)
2063 def test_write_directory(self):
2064 dir_content_types = ('application/directory', 'application/foler')
2065 for type in dir_content_types:
2066 #change content type
2067 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2068 self.client.share_object(self.container, self.object, ['*'], read=False)
2069 self.assert_write(any=True)
2070 self.client.share_object(self.container, self.object, self.authorized, read=False)
2071 self.assert_write(authorized=self.authorized)
2072 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2073 self.assert_write(authorized=self.authorized)
2075 def test_shared_listing(self):
2076 self.client.share_object(self.container, self.object, self.authorized)
2078 my_shared_containers = self.client.list_containers(shared=True)
2079 self.assertEqual(['c'], my_shared_containers)
2080 my_shared_objects = self.client.list_objects('c', shared=True)
2081 self.assertEqual(['o'], my_shared_objects)
2083 dir_content_types = ('application/directory', 'application/foler')
2084 for type in dir_content_types:
2085 #change content type
2086 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2087 my_shared_objects = self.client.list_objects('c', shared=True)
2088 self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2090 for token, account in OTHER_ACCOUNTS.items():
2091 if account in self.authorized:
2092 self.other = Pithos_Client(get_url(), token, account)
2093 self.assertTrue(get_user() in self.other.list_shared_by_others())
2095 class TestPublish(BaseTestCase):
2096 def test_publish(self):
2097 self.client.create_container('c')
2098 o_data = self.upload_random_data('c', 'o')['data']
2099 self.client.publish_object('c', 'o')
2100 meta = self.client.retrieve_object_metadata('c', 'o')
2101 self.assertTrue('x-object-public' in meta)
2102 url = meta['x-object-public']
2104 p = urlparse(get_url())
2105 if p.scheme == 'http':
2106 conn = HTTPConnection(p.netloc)
2107 elif p.scheme == 'https':
2108 conn = HTTPSConnection(p.netloc)
2110 raise Exception('Unknown URL scheme')
2112 conn.request('GET', url)
2113 resp = conn.getresponse()
2114 length = resp.getheader('content-length', None)
2115 data = resp.read(length)
2116 self.assertEqual(o_data, data)
2118 class TestPolicies(BaseTestCase):
2119 def test_none_versioning(self):
2120 self.client.create_container('c', policies={'versioning':'none'})
2121 o = self.upload_random_data('c', 'o')
2122 meta = self.client.retrieve_object_metadata('c', 'o')
2123 v = meta['x-object-version']
2124 more_data = get_random_data()
2125 self.client.update_object('c', 'o', StringIO(more_data))
2126 vlist = self.client.retrieve_object_versionlist('c', 'o')
2127 self.assert_raises_fault(404, self.client.retrieve_object_version,
2129 data = self.client.retrieve_object('c', 'o')
2130 end = len(o['data'])
2131 self.assertEqual(data[:end], o['data'])
2132 self.assertEqual(data[end:], more_data)
2134 def test_quota(self):
2135 self.client.create_container('c', policies={'quota':'1'})
2136 meta = self.client.retrieve_container_metadata('c')
2137 self.assertEqual(meta['x-container-policy-quota'], '1')
2138 self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2141 def test_quota_none(self):
2142 self.client.create_container('c', policies={'quota':'0'})
2143 meta = self.client.retrieve_container_metadata('c')
2144 self.assertEqual(meta['x-container-policy-quota'], '0')
2145 self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2148 class AssertUUidInvariant(object):
2149 def __init__(self, callable, *args, **kwargs):
2150 self.callable = callable
2152 self.kwargs = kwargs
2154 def __enter__(self):
2155 self.map = self.callable(*self.args, **self.kwargs)
2156 assert('x-object-uuid' in self.map)
2157 self.uuid = self.map['x-object-uuid']
2160 def __exit__(self, type, value, tb):
2161 map = self.callable(*self.args, **self.kwargs)
2162 assert('x-object-uuid' in self.map)
2163 uuid = map['x-object-uuid']
2164 assert(uuid == self.uuid)
2166 class AssertMappingInvariant(object):
2167 def __init__(self, callable, *args, **kwargs):
2168 self.callable = callable
2170 self.kwargs = kwargs
2172 def __enter__(self):
2173 self.map = self.callable(*self.args, **self.kwargs)
2176 def __exit__(self, type, value, tb):
2177 map = self.callable(*self.args, **self.kwargs)
2178 for k, v in self.map.items():
2181 #print '#', k, v, map[k]
2185 class AssertContentInvariant(object):
2186 def __init__(self, callable, *args, **kwargs):
2187 self.callable = callable
2189 self.kwargs = kwargs
2191 def __enter__(self):
2192 self.content = self.callable(*self.args, **self.kwargs)[2]
2195 def __exit__(self, type, value, tb):
2196 content = self.callable(*self.args, **self.kwargs)[2]
2197 assert self.content == content
2199 def get_content_splitted(response):
2201 return response.content.split('\n')
2203 def compute_md5_hash(data):
2207 return md5.hexdigest().lower()
2209 def compute_block_hash(data, algorithm):
2210 h = hashlib.new(algorithm)
2211 h.update(data.rstrip('\x00'))
2212 return h.hexdigest()
2214 def get_random_data(length=500):
2215 char_set = string.ascii_uppercase + string.digits
2216 return ''.join(random.choice(char_set) for x in xrange(length))
2219 MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2220 __D = r'(?P<day>\d{2})'
2221 __D2 = r'(?P<day>[ \d]\d)'
2222 __M = r'(?P<mon>\w{3})'
2223 __Y = r'(?P<year>\d{4})'
2224 __Y2 = r'(?P<year>\d{2})'
2225 __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2226 RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2227 RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2228 ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2229 for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2230 m = regex.match(date)
2235 o_names = ['kate.jpg',
2236 'kate_beckinsale.jpg',
2237 'How To Win Friends And Influence People.pdf',
2238 'moms_birthday.jpg',
2240 'Disturbed - Down With The Sickness.mp3',
2241 'army_of_darkness.avi',
2243 'photos/animals/dogs/poodle.jpg',
2244 'photos/animals/dogs/terrier.jpg',
2245 'photos/animals/cats/persian.jpg',
2246 'photos/animals/cats/siamese.jpg',
2247 'photos/plants/fern.jpg',
2248 'photos/plants/rose.jpg',
2253 if get_user() == 'test':
2254 unittest.main(module='pithos.tools.test')
2256 print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2259 if __name__ == "__main__":