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 #wrong manifestation
1271 self.client.create_manifestation(self.container, 'large-object',
1272 '%s/invalid' % self.container)
1273 self.assertEqual('', self.client.retrieve_object(self.container,
1276 def test_create_zero_length_object(self):
1279 zero = self.client.create_zero_length_object(c, o)
1280 zero_meta = self.client.retrieve_object_metadata(c, o)
1281 zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1282 zero_data = self.client.retrieve_object(c, o)
1284 self.assertEqual(int(zero_meta['content-length']), 0)
1285 hasher = newhasher('sha256')
1287 emptyhash = hasher.digest()
1288 self.assertEqual(zero_hash, [hexlify(emptyhash)])
1289 self.assertEqual(zero_data, '')
1291 def test_create_object_by_hashmap(self):
1294 self.upload_random_data(c, o)
1295 hashmap = self.client.retrieve_object(c, o, format='json')
1297 self.client.create_object_by_hashmap(c, o2, hashmap)
1298 self.assertEqual(self.client.retrieve_object(c, o),
1299 self.client.retrieve_object(c, o))
1301 class ObjectCopy(BaseTestCase):
1303 BaseTestCase.setUp(self)
1304 self.containers = ['c1', 'c2']
1305 for c in self.containers:
1306 self.client.create_container(c)
1307 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1309 def test_copy(self):
1310 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1311 self.containers[0], self.obj['name']):
1313 meta = {'test':'testcopy'}
1314 status = self.client.copy_object(self.containers[0],
1320 #assert copy success
1321 self.assertEqual(status, 201)
1323 #assert access the new object
1324 headers = self.client.retrieve_object_metadata(self.containers[0],
1326 self.assertTrue('x-object-meta-test' in headers.keys())
1327 self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1329 #assert etag is the same
1330 self.assertEqual(headers['etag'], self.obj['hash'])
1332 #assert src object still exists
1333 self.assert_object_exists(self.containers[0], self.obj['name'])
1335 def test_copy_from_different_container(self):
1336 with AssertMappingInvariant(self.client.retrieve_object_metadata,
1337 self.containers[0], self.obj['name']):
1338 meta = {'test':'testcopy'}
1339 status = self.client.copy_object(self.containers[0],
1344 self.assertEqual(status, 201)
1346 # assert updated metadata
1347 meta = self.client.retrieve_object_metadata(self.containers[1],
1350 self.assertTrue('test' in meta.keys())
1351 self.assertTrue(meta['test'], 'testcopy')
1353 #assert src object still exists
1354 self.assert_object_exists(self.containers[0], self.obj['name'])
1356 def test_copy_invalid(self):
1357 #copy from invalid object
1358 meta = {'test':'testcopy'}
1359 self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1360 'test.py', self.containers[1], 'testcopy', meta)
1362 #copy from invalid container
1363 meta = {'test':'testcopy'}
1364 self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1365 self.obj['name'], self.containers[1],
1368 class ObjectMove(BaseTestCase):
1370 BaseTestCase.setUp(self)
1371 self.containers = ['c1', 'c2']
1372 for c in self.containers:
1373 self.client.create_container(c)
1374 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1376 def test_move(self):
1377 meta = self.client.retrieve_object_metadata(self.containers[0],
1379 self.assertTrue('x-object-uuid' in meta)
1380 uuid = meta['x-object-uuid']
1383 meta = {'test':'testcopy'}
1384 src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1385 status = self.client.move_object(self.containers[0], self.obj['name'],
1386 self.containers[0], 'testcopy',
1389 #assert successful move
1390 self.assertEqual(status, 201)
1392 #assert updated metadata
1393 meta = self.client.retrieve_object_metadata(self.containers[0],
1395 self.assertTrue('x-object-meta-test' in meta.keys())
1396 self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1399 self.assertTrue(meta['x-object-uuid'], uuid)
1401 #assert src object no more exists
1402 self.assert_object_not_exists(self.containers[0], self.obj['name'])
1404 class ObjectPost(BaseTestCase):
1406 BaseTestCase.setUp(self)
1407 self.containers = ['c1', 'c2']
1408 for c in self.containers:
1409 self.client.create_container(c)
1412 self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1414 def test_update_meta(self):
1415 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1417 self.obj[0]['name']):
1418 #perform update metadata
1419 more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1420 status = self.client.update_object_metadata(self.containers[0],
1421 self.obj[0]['name'],
1423 #assert request accepted
1424 self.assertEqual(status, 202)
1426 #assert old metadata are still there
1427 headers = self.client.retrieve_object_metadata(self.containers[0],
1428 self.obj[0]['name'],
1430 #assert new metadata have been updated
1431 for k,v in more.items():
1432 self.assertTrue(k in headers.keys())
1433 self.assertTrue(headers[k], v)
1436 more = {'f' * 114: 'b' * 257}
1437 self.assert_raises_fault(400, self.client.update_object_metadata,
1439 self.obj[0]['name'],
1442 def test_update_object(self,
1445 instance_length = True,
1446 content_length = 500):
1447 with AssertUUidInvariant(self.client.retrieve_object_metadata,
1449 self.obj[0]['name']):
1450 l = len(self.obj[0]['data'])
1451 range = 'bytes %d-%d/%s' %(first_byte_pos,
1453 l if instance_length else '*')
1454 partial = last_byte_pos - first_byte_pos + 1
1455 length = first_byte_pos + partial
1456 data = get_random_data(partial)
1457 args = {'content_type':'application/octet-stream',
1458 'content_range':'%s' %range}
1460 args['content_length'] = content_length
1462 r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1463 StringIO(data), **args)
1466 if partial < 0 or (instance_length and l <= last_byte_pos):
1467 self.assertEqual(status, 202)
1469 self.assertEqual(status, 204)
1470 #check modified object
1471 content = self.client.retrieve_object(self.containers[0],
1472 self.obj[0]['name'])
1473 self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1474 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1475 self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1476 self.assertEqual(etag, compute_md5_hash(content))
1478 def test_update_object_lt_blocksize(self):
1479 self.test_update_object(10, 20, content_length=None)
1481 def test_update_object_gt_blocksize(self):
1482 o = self.upload_random_data(self.containers[0], o_names[1],
1483 length=4*1024*1024+5)
1484 c = self.containers[0]
1487 first_byte_pos = 4*1024*1024+1
1488 last_byte_pos = 4*1024*1024+4
1489 l = last_byte_pos - first_byte_pos + 1
1490 data = get_random_data(l)
1491 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1492 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1493 content = self.client.retrieve_object(c, o_name)
1494 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1495 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1496 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1498 def test_update_object_divided_by_blocksize(self):
1499 o = self.upload_random_data(self.containers[0], o_names[1],
1500 length=4*1024*1024+5)
1501 c = self.containers[0]
1504 first_byte_pos = 4*1024*1024
1505 last_byte_pos = 5*1024*1024
1506 l = last_byte_pos - first_byte_pos + 1
1507 data = get_random_data(l)
1508 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1509 self.client.update_object(c, o_name, StringIO(data), content_range=range)
1510 content = self.client.retrieve_object(c, o_name)
1511 self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1512 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1513 self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1515 def test_update_object_no_content_length(self):
1516 self.test_update_object(content_length = None)
1518 def test_update_object_invalid_content_length(self):
1519 with AssertContentInvariant(self.client.retrieve_object,
1520 self.containers[0], self.obj[0]['name']):
1521 self.assert_raises_fault(400, self.test_update_object,
1522 content_length = 1000)
1524 def _test_update_object_invalid_range(self):
1525 with AssertContentInvariant(self.client.retrieve_object,
1526 self.containers[0], self.obj[0]['name']):
1527 self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1529 def _test_update_object_invalid_range_and_length(self):
1530 with AssertContentInvariant(self.client.retrieve_object,
1531 self.containers[0], self.obj[0]['name']):
1532 self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1535 def test_update_object_invalid_range_with_no_content_length(self):
1536 with AssertContentInvariant(self.client.retrieve_object,
1537 self.containers[0], self.obj[0]['name']):
1538 self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1539 content_length = None)
1541 def test_update_object_out_of_limits(self):
1542 with AssertContentInvariant(self.client.retrieve_object,
1543 self.containers[0], self.obj[0]['name']):
1544 l = len(self.obj[0]['data'])
1545 self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1547 def test_append(self):
1548 data = get_random_data(500)
1550 self.client.update_object(self.containers[0], self.obj[0]['name'],
1551 StringIO(data), content_length=500,
1552 content_type='application/octet-stream')
1554 content = self.client.retrieve_object(self.containers[0],
1555 self.obj[0]['name'])
1556 self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1557 self.assertEqual(content[:-500], self.obj[0]['data'])
1559 def test_update_with_chunked_transfer(self):
1560 data = get_random_data(500)
1562 fl = len(self.obj[0]['data'])
1564 self.client.update_object_using_chunks(self.containers[0],
1565 self.obj[0]['name'],
1568 content_type='application/octet-stream')
1570 #check modified object
1571 content = self.client.retrieve_object(self.containers[0],
1572 self.obj[0]['name'])
1573 self.assertEqual(content[0:dl], data)
1574 self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1576 def test_update_from_other_object(self):
1577 c = self.containers[0]
1581 source_data = self.client.retrieve_object(c, src)
1582 source_meta = self.client.retrieve_object_metadata(c, src)
1583 source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1585 #update zero length object
1586 self.client.create_zero_length_object(c, dest)
1587 source_object = '/%s/%s' % (c, src)
1588 self.client.update_from_other_source(c, dest, source_object)
1589 dest_data = self.client.retrieve_object(c, src)
1590 dest_meta = self.client.retrieve_object_metadata(c, dest)
1591 dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1592 self.assertEqual(source_data, dest_data)
1593 self.assertEqual(source_hash, dest_hash)
1596 self.client.update_from_other_source(c, dest, source_object)
1597 content = self.client.retrieve_object(c, dest)
1598 self.assertEqual(source_data * 2, content)
1600 def test_update_range_from_other_object(self):
1601 c = self.containers[0]
1605 src = self.obj[1]['name']
1606 src_data = self.client.retrieve_object(c, src)
1608 #update zero length object
1609 prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1610 source_object = '/%s/%s' % (c, src)
1611 first_byte_pos = 4*1024*1024+1
1612 last_byte_pos = 4*1024*1024+4
1613 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1614 self.client.update_from_other_source(c, dest, source_object,
1615 content_range=range)
1616 content = self.client.retrieve_object(c, dest)
1617 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1618 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1619 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1621 def test_update_hashes_from_other_object(self):
1622 c = self.containers[0]
1626 src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1628 #update zero length object
1629 prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1630 source_object = '/%s/%s' % (c, o_names[0])
1631 first_byte_pos = 4*1024*1024
1632 last_byte_pos = 5*1024*1024
1633 range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1634 self.client.update_from_other_source(c, dest, source_object,
1635 content_range=range)
1636 content = self.client.retrieve_object(c, dest)
1637 self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1638 self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1639 self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1642 def test_update_zero_length_object(self):
1643 c = self.containers[0]
1646 zero = self.client.create_zero_length_object(c, o)
1648 data = get_random_data()
1649 self.client.update_object(c, o, StringIO(data))
1650 self.client.create_object(c, other, StringIO(data))
1652 self.assertEqual(self.client.retrieve_object(c, o),
1653 self.client.retrieve_object(c, other))
1655 self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1656 self.client.retrieve_object_hashmap(c, other)["hashes"])
1658 class ObjectDelete(BaseTestCase):
1660 BaseTestCase.setUp(self)
1661 self.containers = ['c1', 'c2']
1662 for c in self.containers:
1663 self.client.create_container(c)
1664 self.obj = self.upload_random_data(self.containers[0], o_names[0])
1666 def test_delete(self):
1667 #perform delete object
1668 self.client.delete_object(self.containers[0], self.obj['name'])[0]
1670 def test_delete_invalid(self):
1671 #assert item not found
1672 self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1675 class ListSharing(BaseTestCase):
1677 BaseTestCase.setUp(self)
1679 self.client.create_container('c%s' %i)
1680 self.client.create_container('c')
1682 self.upload_random_data('c1', 'o%s' %i)
1683 accounts = OTHER_ACCOUNTS.copy()
1684 self.o1_sharing_with = accounts.popitem()
1685 self.o1_sharing = [self.o1_sharing_with[1]]
1686 self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1690 l.append(accounts.popitem())
1692 def test_list_other_shared(self):
1693 self.other = Pithos_Client(get_url(),
1694 self.o1_sharing_with[0],
1695 self.o1_sharing_with[1])
1696 self.assertTrue(get_user() in self.other.list_shared_by_others())
1698 def test_list_my_shared(self):
1699 my_shared_containers = self.client.list_containers(shared=True)
1700 self.assertTrue('c1' in my_shared_containers)
1701 self.assertTrue('c2' not in my_shared_containers)
1703 my_shared_objects = self.client.list_objects('c1', shared=True)
1704 self.assertTrue('o1' in my_shared_objects)
1705 self.assertTrue('o2' not in my_shared_objects)
1707 class TestGreek(BaseTestCase):
1708 def test_create_container(self):
1709 self.client.create_container('φάκελος')
1710 self.assert_container_exists('φάκελος')
1712 self.assertTrue('φάκελος' in self.client.list_containers())
1714 def test_create_object(self):
1715 self.client.create_container('φάκελος')
1716 self.upload_random_data('φάκελος', 'αντικείμενο')
1718 self.assert_object_exists('φάκελος', 'αντικείμενο')
1719 self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1721 def test_copy_object(self):
1722 src_container = 'φάκελος'
1723 src_object = 'αντικείμενο'
1724 dest_container = 'αντίγραφα'
1725 dest_object = 'ασφαλές-αντίγραφο'
1727 self.client.create_container(src_container)
1728 self.upload_random_data(src_container, src_object)
1730 self.client.create_container(dest_container)
1731 self.client.copy_object(src_container, src_object, dest_container,
1734 self.assert_object_exists(src_container, src_object)
1735 self.assert_object_exists(dest_container, dest_object)
1736 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1738 def test_move_object(self):
1739 src_container = 'φάκελος'
1740 src_object = 'αντικείμενο'
1741 dest_container = 'αντίγραφα'
1742 dest_object = 'ασφαλές-αντίγραφο'
1744 self.client.create_container(src_container)
1745 self.upload_random_data(src_container, src_object)
1747 self.client.create_container(dest_container)
1748 self.client.move_object(src_container, src_object, dest_container,
1751 self.assert_object_not_exists(src_container, src_object)
1752 self.assert_object_exists(dest_container, dest_object)
1753 self.assertTrue(dest_object in self.client.list_objects(dest_container))
1755 def test_delete_object(self):
1756 self.client.create_container('φάκελος')
1757 self.upload_random_data('φάκελος', 'αντικείμενο')
1758 self.assert_object_exists('φάκελος', 'αντικείμενο')
1760 self.client.delete_object('φάκελος', 'αντικείμενο')
1761 self.assert_object_not_exists('φάκελος', 'αντικείμενο')
1762 self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
1764 def test_delete_container(self):
1765 self.client.create_container('φάκελος')
1766 self.assert_container_exists('φάκελος')
1768 self.client.delete_container('φάκελος')
1769 self.assert_container_not_exists('φάκελος')
1770 self.assertTrue('φάκελος' not in self.client.list_containers())
1772 def test_account_meta(self):
1773 meta = {'ποιότητα':'ΑΑΑ'}
1774 self.client.update_account_metadata(**meta)
1775 meta = self.client.retrieve_account_metadata(restricted=True)
1776 self.assertTrue('ποιότητα' in meta.keys())
1777 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1779 def test_container_meta(self):
1780 meta = {'ποιότητα':'ΑΑΑ'}
1781 self.client.create_container('φάκελος', **meta)
1783 meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
1784 self.assertTrue('ποιότητα' in meta.keys())
1785 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1787 def test_object_meta(self):
1788 self.client.create_container('φάκελος')
1789 meta = {'ποιότητα':'ΑΑΑ'}
1790 self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
1792 meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
1794 self.assertTrue('ποιότητα' in meta.keys())
1795 self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1797 def test_list_meta_filtering(self):
1798 self.client.create_container('φάκελος')
1799 meta = {'ποιότητα':'ΑΑΑ'}
1800 self.upload_random_data('φάκελος', 'ο1', **meta)
1801 self.upload_random_data('φάκελος', 'ο2')
1802 self.upload_random_data('φάκελος', 'ο3')
1804 meta = {'ποσότητα':'μεγάλη'}
1805 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1806 objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
1807 self.assertEquals(objects, ['ο1', 'ο2'])
1809 objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
1810 self.assertEquals(objects, ['ο2', 'ο3'])
1812 objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
1813 self.assertEquals(objects, ['ο3'])
1815 meta = {'ποιότητα':'ΑΒ'}
1816 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1817 objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
1818 self.assertEquals(objects, ['ο1'])
1819 objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
1820 self.assertEquals(objects, ['ο2'])
1822 meta = {'έτος':'2011'}
1823 self.client.update_object_metadata('φάκελος', 'ο3', **meta)
1824 meta = {'έτος':'2012'}
1825 self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1826 objects = self.client.list_objects('φάκελος', meta='έτος<2012')
1827 self.assertEquals(objects, ['ο3'])
1828 objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
1829 self.assertEquals(objects, ['ο2', 'ο3'])
1830 objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
1831 self.assertEquals(objects, '')
1833 def test_groups(self):
1835 groups = {'σεφς':'chazapis,διογένης'}
1836 self.client.set_account_groups(**groups)
1837 groups.update(self.initial_groups)
1838 self.assertEqual(groups['σεφς'],
1839 self.client.retrieve_account_groups()['σεφς'])
1842 self.client.create_container('φάκελος')
1843 o = self.upload_random_data('φάκελος', 'ο1')
1844 self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
1845 chef = Pithos_Client(get_url(),
1848 self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
1849 'φάκελος', 'ο1', account=get_user())
1852 self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
1853 new_data = get_random_data()
1854 self.assert_not_raises_fault(403, chef.update_object,
1855 'φάκελος', 'ο1', StringIO(new_data),
1858 server_data = self.client.retrieve_object('φάκελος', 'ο1')
1859 self.assertEqual(server_data[:len(o['data'])], o['data'])
1860 self.assertEqual(server_data[len(o['data']):], new_data)
1862 def test_manifestation(self):
1863 self.client.create_container('κουβάς')
1867 part = '%s%d' %(prefix, i)
1868 o = self.upload_random_data('κουβάς', part)
1871 self.client.create_container('φάκελος')
1872 manifest = '%s/%s' %('κουβάς', prefix)
1873 self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
1875 self.assert_object_exists('φάκελος', 'άπαντα')
1876 self.assertEqual(data, self.client.retrieve_object('φάκελος',
1879 #wrong manifestation
1880 self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
1881 self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
1883 def test_update_from_another_object(self):
1884 self.client.create_container('κουβάς')
1885 src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
1886 initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
1887 source_object = '/%s/%s' % ('κουβάς', 'πηγή')
1888 self.client.update_from_other_source('κουβάς', 'νέο', source_object)
1891 self.client.retrieve_object('κουβάς', 'νέο'),
1892 '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
1894 class TestPermissions(BaseTestCase):
1896 BaseTestCase.setUp(self)
1899 self.authorized = ['chazapis', 'verigak', 'gtsouk']
1900 groups = {'pithosdev':','.join(self.authorized)}
1901 self.client.set_account_groups(**groups)
1903 self.container = 'c'
1905 self.client.create_container(self.container)
1906 self.upload_random_data(self.container, self.object)
1907 self.upload_random_data(self.container, self.object+'/')
1908 self.upload_random_data(self.container, self.object+'/a')
1909 self.upload_random_data(self.container, self.object+'a')
1910 self.upload_random_data(self.container, self.object+'a/')
1911 self.dir_content_types = ('application/directory', 'application/folder')
1913 def assert_read(self, authorized=[], any=False, depth=0):
1914 for token, account in OTHER_ACCOUNTS.items():
1915 cl = Pithos_Client(get_url(), token, account)
1916 if account in authorized or any:
1917 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
1918 self.container, self.object,
1921 self.assert_raises_fault(403, cl.retrieve_object_metadata,
1922 self.container, self.object,
1926 meta = self.client.retrieve_object_metadata(self.container, self.object)
1927 type = meta['content-type']
1928 derivatives = self.client.list_objects(self.container, prefix=self.object)
1929 #exclude the self.object
1930 del derivatives[derivatives.index(self.object)]
1931 for o in derivatives:
1932 for token, account in OTHER_ACCOUNTS.items():
1933 cl = Pithos_Client(get_url(), token, account)
1934 prefix = self.object if self.object.endswith('/') else self.object+'/'
1935 if (account in authorized or any) and \
1936 (type in self.dir_content_types) and \
1937 o.startswith(prefix):
1938 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
1939 self.container, o, account=get_user())
1941 self.assert_raises_fault(403, cl.retrieve_object_metadata,
1942 self.container, o, account=get_user())
1944 def assert_write(self, authorized=[], any=False):
1945 o_data = self.client.retrieve_object(self.container, self.object)
1946 for token, account in OTHER_ACCOUNTS.items():
1947 cl = Pithos_Client(get_url(), token, account)
1948 new_data = get_random_data()
1949 if account in authorized or any:
1951 self.assert_not_raises_fault(403, cl.update_object,
1952 self.container, self.object, StringIO(new_data),
1956 server_data = cl.retrieve_object(self.container, self.object, account=get_user())
1957 self.assertEqual(o_data, server_data[:len(o_data)])
1958 self.assertEqual(new_data, server_data[len(o_data):])
1959 o_data = server_data
1961 self.failIf(f.status == 403)
1963 self.assert_raises_fault(403, cl.update_object,
1964 self.container, self.object, StringIO(new_data),
1967 meta = self.client.retrieve_object_metadata(self.container, self.object)
1968 type = meta['content-type']
1969 derivatives = self.client.list_objects(self.container, prefix=self.object)
1971 del derivatives[derivatives.index(self.object)]
1972 for o in derivatives:
1973 for token, account in OTHER_ACCOUNTS.items():
1974 prefix = self.object if self.object.endswith('/') else self.object+'/'
1975 cl = Pithos_Client(get_url(), token, account)
1976 new_data = get_random_data()
1977 if (account in authorized or any) and \
1978 (type in self.dir_content_types) and \
1979 o.startswith(prefix):
1981 self.assert_not_raises_fault(403, cl.update_object,
1986 server_data = cl.retrieve_object(self.container, o, account=get_user())
1987 self.assertEqual(new_data, server_data[-len(new_data):])
1989 self.failIf(f.status == 403)
1991 self.assert_raises_fault(403, cl.update_object,
1996 def test_group_read(self):
1997 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
1998 self.assert_read(authorized=self.authorized)
2000 def test_read_many(self):
2001 self.client.share_object(self.container, self.object, self.authorized)
2002 self.assert_read(authorized=self.authorized)
2004 def test_read_by_everyone(self):
2005 self.client.share_object(self.container, self.object, ['*'])
2006 self.assert_read(any=True)
2008 def test_read_directory(self):
2009 for type in self.dir_content_types:
2010 #change content type
2011 self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2012 self.client.share_object(self.container, self.object, ['*'])
2013 self.assert_read(any=True)
2014 self.client.share_object(self.container, self.object, self.authorized)
2015 self.assert_read(authorized=self.authorized)
2016 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2017 self.assert_read(authorized=self.authorized)
2019 def test_group_write(self):
2020 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2021 self.assert_write(authorized=self.authorized)
2023 def test_write_many(self):
2024 self.client.share_object(self.container, self.object, self.authorized, read=False)
2025 self.assert_write(authorized=self.authorized)
2027 def test_write_by_everyone(self):
2028 self.client.share_object(self.container, self.object, ['*'], read=False)
2029 self.assert_write(any=True)
2031 def test_write_directory(self):
2032 dir_content_types = ('application/directory', 'application/foler')
2033 for type in dir_content_types:
2034 #change content type
2035 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2036 self.client.share_object(self.container, self.object, ['*'], read=False)
2037 self.assert_write(any=True)
2038 self.client.share_object(self.container, self.object, self.authorized, read=False)
2039 self.assert_write(authorized=self.authorized)
2040 self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2041 self.assert_write(authorized=self.authorized)
2043 def test_shared_listing(self):
2044 self.client.share_object(self.container, self.object, self.authorized)
2046 my_shared_containers = self.client.list_containers(shared=True)
2047 self.assertEqual(['c'], my_shared_containers)
2048 my_shared_objects = self.client.list_objects('c', shared=True)
2049 self.assertEqual(['o'], my_shared_objects)
2051 dir_content_types = ('application/directory', 'application/foler')
2052 for type in dir_content_types:
2053 #change content type
2054 self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2055 my_shared_objects = self.client.list_objects('c', shared=True)
2056 self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2058 for token, account in OTHER_ACCOUNTS.items():
2059 if account in self.authorized:
2060 self.other = Pithos_Client(get_url(), token, account)
2061 self.assertTrue(get_user() in self.other.list_shared_by_others())
2063 class TestPublish(BaseTestCase):
2064 def test_publish(self):
2065 self.client.create_container('c')
2066 o_data = self.upload_random_data('c', 'o')['data']
2067 self.client.publish_object('c', 'o')
2068 meta = self.client.retrieve_object_metadata('c', 'o')
2069 self.assertTrue('x-object-public' in meta)
2070 url = meta['x-object-public']
2072 p = urlparse(get_url())
2073 if p.scheme == 'http':
2074 conn = HTTPConnection(p.netloc)
2075 elif p.scheme == 'https':
2076 conn = HTTPSConnection(p.netloc)
2078 raise Exception('Unknown URL scheme')
2080 conn.request('GET', url)
2081 resp = conn.getresponse()
2082 length = resp.getheader('content-length', None)
2083 data = resp.read(length)
2084 self.assertEqual(o_data, data)
2086 class TestPolicies(BaseTestCase):
2087 def test_none_versioning(self):
2088 self.client.create_container('c', policies={'versioning':'none'})
2089 o = self.upload_random_data('c', 'o')
2090 meta = self.client.retrieve_object_metadata('c', 'o')
2091 v = meta['x-object-version']
2092 more_data = get_random_data()
2093 self.client.update_object('c', 'o', StringIO(more_data))
2094 vlist = self.client.retrieve_object_versionlist('c', 'o')
2095 self.assert_raises_fault(404, self.client.retrieve_object_version,
2097 data = self.client.retrieve_object('c', 'o')
2098 end = len(o['data'])
2099 self.assertEqual(data[:end], o['data'])
2100 self.assertEqual(data[end:], more_data)
2102 def test_quota(self):
2103 self.client.create_container('c', policies={'quota':'1'})
2104 meta = self.client.retrieve_container_metadata('c')
2105 self.assertEqual(meta['x-container-policy-quota'], '1')
2106 self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2109 def test_quota_none(self):
2110 self.client.create_container('c', policies={'quota':'0'})
2111 meta = self.client.retrieve_container_metadata('c')
2112 self.assertEqual(meta['x-container-policy-quota'], '0')
2113 self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2116 class AssertUUidInvariant(object):
2117 def __init__(self, callable, *args, **kwargs):
2118 self.callable = callable
2120 self.kwargs = kwargs
2122 def __enter__(self):
2123 self.map = self.callable(*self.args, **self.kwargs)
2124 assert('x-object-uuid' in self.map)
2125 self.uuid = self.map['x-object-uuid']
2128 def __exit__(self, type, value, tb):
2129 map = self.callable(*self.args, **self.kwargs)
2130 assert('x-object-uuid' in self.map)
2131 uuid = map['x-object-uuid']
2132 assert(uuid == self.uuid)
2134 class AssertMappingInvariant(object):
2135 def __init__(self, callable, *args, **kwargs):
2136 self.callable = callable
2138 self.kwargs = kwargs
2140 def __enter__(self):
2141 self.map = self.callable(*self.args, **self.kwargs)
2144 def __exit__(self, type, value, tb):
2145 map = self.callable(*self.args, **self.kwargs)
2146 for k, v in self.map.items():
2149 #print '#', k, v, map[k]
2153 class AssertContentInvariant(object):
2154 def __init__(self, callable, *args, **kwargs):
2155 self.callable = callable
2157 self.kwargs = kwargs
2159 def __enter__(self):
2160 self.content = self.callable(*self.args, **self.kwargs)[2]
2163 def __exit__(self, type, value, tb):
2164 content = self.callable(*self.args, **self.kwargs)[2]
2165 assert self.content == content
2167 def get_content_splitted(response):
2169 return response.content.split('\n')
2171 def compute_md5_hash(data):
2175 return md5.hexdigest().lower()
2177 def compute_block_hash(data, algorithm):
2178 h = hashlib.new(algorithm)
2179 h.update(data.rstrip('\x00'))
2180 return h.hexdigest()
2182 def get_random_data(length=500):
2183 char_set = string.ascii_uppercase + string.digits
2184 return ''.join(random.choice(char_set) for x in xrange(length))
2187 MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2188 __D = r'(?P<day>\d{2})'
2189 __D2 = r'(?P<day>[ \d]\d)'
2190 __M = r'(?P<mon>\w{3})'
2191 __Y = r'(?P<year>\d{4})'
2192 __Y2 = r'(?P<year>\d{2})'
2193 __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2194 RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2195 RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2196 ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2197 for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2198 m = regex.match(date)
2203 o_names = ['kate.jpg',
2204 'kate_beckinsale.jpg',
2205 'How To Win Friends And Influence People.pdf',
2206 'moms_birthday.jpg',
2208 'Disturbed - Down With The Sickness.mp3',
2209 'army_of_darkness.avi',
2211 'photos/animals/dogs/poodle.jpg',
2212 'photos/animals/dogs/terrier.jpg',
2213 'photos/animals/cats/persian.jpg',
2214 'photos/animals/cats/siamese.jpg',
2215 'photos/plants/fern.jpg',
2216 'photos/plants/rose.jpg',
2221 if get_user() == 'test':
2224 print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2227 if __name__ == "__main__":