Call for delete container contents
[pithos] / snf-pithos-tools / pithos / tools / test.py
1 #!/usr/bin/env python
2 #coding=utf8
3
4 # Copyright 2011-2012 GRNET S.A. All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or
7 # without modification, are permitted provided that the following
8 # conditions are met:
9 #
10 #   1. Redistributions of source code must retain the above
11 #      copyright notice, this list of conditions and the following
12 #      disclaimer.
13 #
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.
18 #
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.
31 #
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.
36
37 from pithos.tools.lib.client import Pithos_Client, Fault
38 from pithos.tools.lib.util import get_user, get_auth, get_url
39
40 from xml.dom import minidom
41 from StringIO import StringIO
42 from hashlib import new as newhasher
43 from binascii import hexlify
44 from httplib import HTTPConnection, HTTPSConnection
45 from urlparse import urlparse
46
47 import json
48 import unittest
49 import time as _time
50 import types
51 import hashlib
52 import mimetypes
53 import random
54 import datetime
55 import string
56 import re
57
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"]
61
62 OTHER_ACCOUNTS = {
63     '0001': 'verigak',
64     '0002': 'chazapis',
65     '0003': 'gtsouk',
66     '0004': 'papagian',
67     '0005': 'louridas',
68     '0006': 'chstath',
69     '0007': 'pkanavos',
70     '0008': 'mvasilak',
71     '0009': 'διογένης'}
72
73 class BaseTestCase(unittest.TestCase):
74     #TODO unauthorized request
75     def setUp(self):
76         self.client = Pithos_Client(get_url(), get_auth(), get_user())
77         self._clean_account()
78         self.invalid_client = Pithos_Client(get_url(), get_auth(), 'invalid')
79
80         #keep track of initial account groups
81         self.initial_groups = self.client.retrieve_account_groups()
82
83         #keep track of initial account meta
84         self.initial_meta = self.client.retrieve_account_metadata(restricted=True)
85
86         self.extended = {
87             'container':(
88                 'name',
89                 'count',
90                 'bytes',
91                 'last_modified',
92                 'x_container_policy'),
93             'object':(
94                 'name',
95                 'hash',
96                 'bytes',
97                 'content_type',
98                 'content_encoding',
99                 'last_modified',)}
100         self.return_codes = (400, 401, 403, 404, 503,)
101
102     def tearDown(self):
103         #delete additionally created meta
104         l = []
105         for m in self.client.retrieve_account_metadata(restricted=True):
106             if m not in self.initial_meta:
107                 l.append(m)
108         self.client.delete_account_metadata(l)
109
110         #delete additionally created groups
111         l = []
112         for g in self.client.retrieve_account_groups():
113             if g not in self.initial_groups:
114                 l.append(g)
115         self.client.unset_account_groups(l)
116         self._clean_account()
117
118     def _clean_account(self):
119         for c in self.client.list_containers():
120             self.client.delete_container(c, delimiter='/')
121             self.client.delete_container(c)
122     
123     def assert_status(self, status, codes):
124         l = [elem for elem in self.return_codes]
125         if type(codes) == types.ListType:
126             l.extend(codes)
127         else:
128             l.append(codes)
129         self.assertTrue(status in l)
130
131     def assert_extended(self, data, format, type, size=10000):
132         if format == 'xml':
133             self._assert_xml(data, type, size)
134         elif format == 'json':
135             self._assert_json(data, type, size)
136
137     def _assert_json(self, data, type, size):
138         convert = lambda s: s.lower()
139         info = [convert(elem) for elem in self.extended[type]]
140         self.assertTrue(len(data) <= size)
141         for item in info:
142             for i in data:
143                 if 'subdir' in i.keys():
144                     continue
145                 self.assertTrue(item in i.keys())
146
147     def _assert_xml(self, data, type, size):
148         convert = lambda s: s.lower()
149         info = [convert(elem) for elem in self.extended[type]]
150         try:
151             info.remove('content_encoding')
152         except ValueError:
153             pass
154         xml = data
155         entities = xml.getElementsByTagName(type)
156         self.assertTrue(len(entities) <= size)
157         for e in entities:
158             for item in info:
159                 self.assertTrue(e.getElementsByTagName(item))
160
161     def assert_raises_fault(self, status, callableObj, *args, **kwargs):
162         """
163         asserts that a Fault with a specific status is raised
164         when callableObj is called with the specific arguments
165         """
166         try:
167             r = callableObj(*args, **kwargs)
168             self.fail('Should never reach here')
169         except Fault, f:
170             if type(status) == types.ListType:
171                 self.failUnless(f.status in status)
172             else:
173                 self.failUnless(f.status == status)
174
175     def assert_not_raises_fault(self, status, callableObj, *args, **kwargs):
176         """
177         asserts that a Fault with a specific status is not raised
178         when callableObj is called with the specific arguments
179         """
180         try:
181             r = callableObj(*args, **kwargs)
182         except Fault, f:
183             self.failIfEqual(f.status, status)
184
185     def assert_container_exists(self, container):
186         """
187         asserts the existence of a container
188         """
189         try:
190             self.client.retrieve_container_metadata(container)
191         except Fault, f:
192             self.failIf(f.status == 404)
193
194     def assert_container_not_exists(self, container):
195         """
196         asserts there is no such a container
197         """
198         self.assert_raises_fault(404, self.client.retrieve_container_metadata,
199                                  container)
200
201     def assert_object_exists(self, container, object):
202         """
203         asserts the existence of an object
204         """
205         try:
206             self.client.retrieve_object_metadata(container, object)
207         except Fault, f:
208             self.failIf(f.status == 404)
209
210     def assert_object_not_exists(self, container, object):
211         """
212         asserts there is no such an object
213         """
214         self.assert_raises_fault(404, self.client.retrieve_object_metadata,
215                                  container, object)
216
217     def assert_versionlist_structure(self, versionlist):
218         self.assertTrue(type(versionlist) == types.ListType)
219         for elem in versionlist:
220             self.assertTrue(type(elem) == types.ListType)
221             self.assertEqual(len(elem), 2)
222
223     def upload_random_data(self, container, name, length=1024, type=None,
224                            enc=None, **meta):
225         data = get_random_data(length)
226         return self.upload_data(container, name, data, type, enc, **meta)
227
228     def upload_data(self, container, name, data, type=None, enc=None, etag=None,
229                     **meta):
230         obj = {}
231         obj['name'] = name
232         try:
233             obj['data'] = data
234             obj['hash'] = compute_md5_hash(obj['data'])
235
236             args = {}
237             args['etag'] = etag if etag else obj['hash']
238
239             try:
240                 guess = mimetypes.guess_type(name)
241                 type = type if type else guess[0]
242                 enc = enc if enc else guess[1]
243             except:
244                 pass
245             args['content_type'] = type if type else 'plain/text'
246             args['content_encoding'] = enc if enc else None
247
248             obj['meta'] = args
249
250             path = '/%s/%s' % (container, name)
251             self.client.create_object(container, name, f=StringIO(obj['data']),
252                                       meta=meta, **args)
253
254             return obj
255         except IOError:
256             return
257
258 class AccountHead(BaseTestCase):
259     def setUp(self):
260         BaseTestCase.setUp(self)
261         self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
262         for item in self.containers:
263             self.client.create_container(item)
264
265         meta = {'foo':'bar'}
266         self.client.update_account_metadata(**meta)
267         #self.updated_meta = self.initial_meta.update(meta)
268
269     def test_get_account_meta(self):
270         meta = self.client.retrieve_account_metadata()
271
272         containers = self.client.list_containers()
273         l = str(len(containers))
274         self.assertEqual(meta['x-account-container-count'], l)
275         size = 0
276         for c in containers:
277             m = self.client.retrieve_container_metadata(c)
278             size = size + int(m['x-container-bytes-used'])
279         self.assertEqual(meta['x-account-bytes-used'], str(size))
280
281     def test_get_account_403(self):
282         self.assert_raises_fault(403,
283                                  self.invalid_client.retrieve_account_metadata)
284
285     def test_get_account_meta_until(self):
286         t = datetime.datetime.utcnow()
287         past = t - datetime.timedelta(minutes=-15)
288         past = int(_time.mktime(past.timetuple()))
289
290         meta = {'premium':True}
291         self.client.update_account_metadata(**meta)
292         meta = self.client.retrieve_account_metadata(restricted=True,
293                                                      until=past)
294         self.assertTrue('premium' not in meta)
295
296         meta = self.client.retrieve_account_metadata(restricted=True)
297         self.assertTrue('premium' in meta)
298
299     def test_get_account_meta_until_invalid_date(self):
300         meta = {'premium':True}
301         self.client.update_account_metadata(**meta)
302         meta = self.client.retrieve_account_metadata(restricted=True,
303                                                      until='kshfksfh')
304         self.assertTrue('premium' in meta)
305
306 class AccountGet(BaseTestCase):
307     def setUp(self):
308         BaseTestCase.setUp(self)
309         #create some containers
310         self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
311         for item in self.containers:
312             self.client.create_container(item)
313
314     def test_list(self):
315         #list containers
316         containers = self.client.list_containers()
317         self.assertEquals(self.containers, containers)
318
319     def test_list_403(self):
320         self.assert_raises_fault(403, self.invalid_client.list_containers)
321
322     def test_list_with_limit(self):
323         limit = 2
324         containers = self.client.list_containers(limit=limit)
325         self.assertEquals(len(containers), limit)
326         self.assertEquals(self.containers[:2], containers)
327
328     def test_list_with_marker(self):
329         l = 2
330         m = 'bananas'
331         containers = self.client.list_containers(limit=l, marker=m)
332         i = self.containers.index(m) + 1
333         self.assertEquals(self.containers[i:(i+l)], containers)
334
335         m = 'oranges'
336         containers = self.client.list_containers(limit=l, marker=m)
337         i = self.containers.index(m) + 1
338         self.assertEquals(self.containers[i:(i+l)], containers)
339
340     def test_list_json_with_marker(self):
341         l = 2
342         m = 'bananas'
343         containers = self.client.list_containers(limit=l, marker=m, format='json')
344         self.assert_extended(containers, 'json', 'container', l)
345         self.assertEqual(containers[0]['name'], 'kiwis')
346         self.assertEqual(containers[1]['name'], 'oranges')
347
348     def test_list_xml_with_marker(self):
349         l = 2
350         m = 'oranges'
351         xml = self.client.list_containers(limit=l, marker=m, format='xml')
352         self.assert_extended(xml, 'xml', 'container', l)
353         nodes = xml.getElementsByTagName('name')
354         self.assertEqual(len(nodes), 1)
355         self.assertEqual(nodes[0].childNodes[0].data, 'pears')
356
357     def test_if_modified_since(self):
358         t = datetime.datetime.utcnow()
359         t2 = t - datetime.timedelta(minutes=10)
360
361         #add a new container
362         self.client.create_container('dummy')
363
364         for f in DATE_FORMATS:
365             past = t2.strftime(f)
366             try:
367                 c = self.client.list_containers(if_modified_since=past)
368                 self.assertEqual(len(c), len(self.containers) + 1)
369             except Fault, f:
370                 self.failIf(f.status == 304) #fail if not modified
371         
372
373     def test_if_modified_since_invalid_date(self):
374         c = self.client.list_containers(if_modified_since='')
375         self.assertEqual(len(c), len(self.containers))
376
377     def test_if_not_modified_since(self):
378         now = datetime.datetime.utcnow()
379         since = now + datetime.timedelta(1)
380
381         for f in DATE_FORMATS:
382             args = {'if_modified_since':'%s' %since.strftime(f)}
383
384             #assert not modified
385             self.assert_raises_fault(304, self.client.list_containers, **args)
386
387     def test_if_unmodified_since(self):
388         now = datetime.datetime.utcnow()
389         since = now + datetime.timedelta(1)
390
391         for f in DATE_FORMATS:
392             c = self.client.list_containers(if_unmodified_since=since.strftime(f))
393
394             #assert success
395             self.assertEqual(self.containers, c)
396
397     def test_if_unmodified_since_precondition_failed(self):
398         t = datetime.datetime.utcnow()
399         t2 = t - datetime.timedelta(minutes=10)
400
401         #add a new container
402         self.client.create_container('dummy')
403
404         for f in DATE_FORMATS:
405             past = t2.strftime(f)
406
407             args = {'if_unmodified_since':'%s' %past}
408
409             #assert precondition failed
410             self.assert_raises_fault(412, self.client.list_containers, **args)
411
412 class AccountPost(BaseTestCase):
413     def setUp(self):
414         BaseTestCase.setUp(self)
415         self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
416         for item in self.containers:
417             self.client.create_container(item)
418
419         meta = {'foo':'bar'}
420         self.client.update_account_metadata(**meta)
421         self.updated_meta = self.initial_meta.update(meta)
422
423     def test_update_meta(self):
424         with AssertMappingInvariant(self.client.retrieve_account_groups):
425             meta = {'test':'test', 'tost':'tost'}
426             self.client.update_account_metadata(**meta)
427
428             meta.update(self.initial_meta)
429             self.assertEqual(meta,
430                              self.client.retrieve_account_metadata(
431                                 restricted=True))
432
433     def test_invalid_account_update_meta(self):
434         meta = {'test':'test', 'tost':'tost'}
435         self.assert_raises_fault(403,
436                                  self.invalid_client.update_account_metadata,
437                                  **meta)
438
439     def test_reset_meta(self):
440         with AssertMappingInvariant(self.client.retrieve_account_groups):
441             meta = {'test':'test', 'tost':'tost'}
442             self.client.update_account_metadata(**meta)
443
444             meta = {'test':'test33'}
445             self.client.reset_account_metadata(**meta)
446
447             self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
448
449     def test_delete_meta(self):
450         with AssertMappingInvariant(self.client.retrieve_account_groups):
451             meta = {'test':'test', 'tost':'tost'}
452             self.client.update_account_metadata(**meta)
453
454             self.client.delete_account_metadata(meta.keys())
455
456             account_meta = self.client.retrieve_account_metadata(restricted=True)
457             for m in meta:
458                 self.assertTrue(m not in account_meta.keys())
459
460     def test_set_account_groups(self):
461         with AssertMappingInvariant(self.client.retrieve_account_metadata):
462             groups = {'pithosdev':'verigak,gtsouk,chazapis'}
463             self.client.set_account_groups(**groups)
464
465             self.assertEqual(set(groups['pithosdev']),
466                              set(self.client.retrieve_account_groups()['pithosdev']))
467
468             more_groups = {'clientsdev':'pkanavos,mvasilak'}
469             self.client.set_account_groups(**more_groups)
470
471             groups.update(more_groups)
472             self.assertEqual(set(groups['clientsdev']),
473                              set(self.client.retrieve_account_groups()['clientsdev']))
474
475     def test_reset_account_groups(self):
476         with AssertMappingInvariant(self.client.retrieve_account_metadata):
477             groups = {'pithosdev':'verigak,gtsouk,chazapis',
478                       'clientsdev':'pkanavos,mvasilak'}
479             self.client.set_account_groups(**groups)
480
481             self.assertEqual(set(groups['pithosdev'].split(',')),
482                              set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
483             self.assertEqual(set(groups['clientsdev'].split(',')),
484                              set(self.client.retrieve_account_groups()['clientsdev'].split(',')))
485
486             groups = {'pithosdev':'verigak,gtsouk,chazapis,papagian'}
487             self.client.reset_account_groups(**groups)
488
489             self.assertEqual(set(groups['pithosdev'].split(',')),
490                              set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
491
492     def test_delete_account_groups(self):
493         with AssertMappingInvariant(self.client.retrieve_account_metadata):
494             groups = {'pithosdev':'verigak,gtsouk,chazapis',
495                       'clientsdev':'pkanavos,mvasilak'}
496             self.client.set_account_groups(**groups)
497
498             self.client.unset_account_groups(groups.keys())
499
500             self.assertEqual({}, self.client.retrieve_account_groups())
501
502 class ContainerHead(BaseTestCase):
503     def setUp(self):
504         BaseTestCase.setUp(self)
505         self.container = 'apples'
506         self.client.create_container(self.container)
507
508     def test_get_meta(self):
509         meta = {'trash':'true'}
510         t1 = datetime.datetime.utcnow()
511         o = self.upload_random_data(self.container, o_names[0], **meta)
512         if o:
513             headers = self.client.retrieve_container_metadata(self.container)
514             self.assertEqual(headers['x-container-object-count'], '1')
515             self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
516             t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
517             delta = (t2 - t1)
518             threashold = datetime.timedelta(seconds=1)
519             self.assertTrue(delta < threashold)
520             self.assertTrue(headers['x-container-object-meta'])
521             self.assertTrue('Trash' in headers['x-container-object-meta'])
522
523 class ContainerGet(BaseTestCase):
524     def setUp(self):
525         BaseTestCase.setUp(self)
526         self.container = ['pears', 'apples']
527         for c in self.container:
528             self.client.create_container(c)
529         self.obj = []
530         for o in o_names[:8]:
531             self.obj.append(self.upload_random_data(self.container[0], o))
532         for o in o_names[8:]:
533             self.obj.append(self.upload_random_data(self.container[1], o))
534     
535     def test_list_shared(self):
536         self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
537         objs = self.client.list_objects(self.container[0], shared=True)
538         self.assertEqual(objs, [self.obj[0]['name']])
539         
540         # create child object
541         self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
542         objs = self.client.list_objects(self.container[0], shared=True)
543         self.assertEqual(objs, [self.obj[0]['name']])
544         
545         # test inheritance
546         self.client.create_folder(self.container[1], 'folder')
547         self.client.share_object(self.container[1], 'folder', ('*',))
548         self.upload_random_data(self.container[1], 'folder/object')
549         objs = self.client.list_objects(self.container[1], shared=True)
550         self.assertEqual(objs, ['folder', 'folder/object'])
551     
552     def test_list_public(self):
553         self.client.publish_object(self.container[0], self.obj[0]['name'])
554         objs = self.client.list_objects(self.container[0], public=True)
555         self.assertEqual(objs, [self.obj[0]['name']])
556         
557         # create child object
558         self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
559         objs = self.client.list_objects(self.container[0], public=True)
560         self.assertEqual(objs, [self.obj[0]['name']])
561         
562         # test inheritance
563         self.client.create_folder(self.container[1], 'folder')
564         self.client.publish_object(self.container[1], 'folder')
565         self.upload_random_data(self.container[1], 'folder/object')
566         objs = self.client.list_objects(self.container[1], public=True)
567         self.assertEqual(objs, ['folder'])
568     
569     def test_list_shared_public(self):
570         self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
571         self.client.publish_object(self.container[0], self.obj[1]['name'])
572         objs = self.client.list_objects(self.container[0], shared=True, public=True)
573         self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
574         
575         # create child object
576         self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
577         self.upload_random_data(self.container[0], strnextling(self.obj[1]['name']))
578         objs = self.client.list_objects(self.container[0], shared=True, public=True)
579         self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
580         
581         # test inheritance
582         self.client.create_folder(self.container[1], 'folder1')
583         self.client.share_object(self.container[1], 'folder1', ('*',))
584         self.upload_random_data(self.container[1], 'folder1/object')
585         self.client.create_folder(self.container[1], 'folder2')
586         self.client.publish_object(self.container[1], 'folder2')
587         o = self.upload_random_data(self.container[1], 'folder2/object')
588         objs = self.client.list_objects(self.container[1], shared=True, public=True)
589         self.assertEqual(objs, ['folder1', 'folder1/object', 'folder2'])
590     
591     def test_list_objects(self):
592         objects = self.client.list_objects(self.container[0])
593         l = [elem['name'] for elem in self.obj[:8]]
594         l.sort()
595         self.assertEqual(objects, l)
596
597     def test_list_objects_containing_slash(self):
598         self.client.create_container('test')
599         self.upload_random_data('test', '/objectname')
600
601         objects = self.client.list_objects('test')
602         self.assertEqual(objects, ['/objectname'])
603
604         objects = self.client.list_objects('test', format='json')
605         self.assertEqual(objects[0]['name'], '/objectname')
606
607         objects = self.client.list_objects('test', format='xml')
608         self.assert_extended(objects, 'xml', 'object')
609         node_name = objects.getElementsByTagName('name')[0]
610         self.assertEqual(node_name.firstChild.data, '/objectname')
611
612     def test_list_objects_with_limit_marker(self):
613         objects = self.client.list_objects(self.container[0], limit=2)
614         l = [elem['name'] for elem in self.obj[:8]]
615         l.sort()
616         self.assertEqual(objects, l[:2])
617
618         markers = ['How To Win Friends And Influence People.pdf',
619                    'moms_birthday.jpg']
620         limit = 4
621         for m in markers:
622             objects = self.client.list_objects(self.container[0], limit=limit,
623                                                marker=m)
624             l = [elem['name'] for elem in self.obj[:8]]
625             l.sort()
626             start = l.index(m) + 1
627             end = start + limit
628             end = end if len(l) >= end else len(l)
629             self.assertEqual(objects, l[start:end])
630
631     #takes too long
632     def _test_list_limit_exceeds(self):
633         self.client.create_container('pithos')
634
635         for i in range(10001):
636             self.client.create_zero_length_object('pithos', i)
637
638         self.assertEqual(10000, len(self.client.list_objects('pithos')))
639
640     def test_list_empty_params(self):
641         objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
642         if objects:
643             objects = objects.strip().split('\n')
644         self.assertEqual(objects,
645                          self.client.list_objects(self.container[0]))
646
647     def test_list_pseudo_hierarchical_folders(self):
648         objects = self.client.list_objects(self.container[1], prefix='photos',
649                                            delimiter='/')
650         self.assertEquals(['photos/animals/', 'photos/me.jpg',
651                            'photos/plants/'], objects)
652
653         objects = self.client.list_objects(self.container[1],
654                                            prefix='photos/animals',
655                                            delimiter='/')
656         l = ['photos/animals/cats/', 'photos/animals/dogs/']
657         self.assertEquals(l, objects)
658
659         objects = self.client.list_objects(self.container[1], path='photos')
660         self.assertEquals(['photos/me.jpg'], objects)
661
662     def test_extended_list_json(self):
663         objects = self.client.list_objects(self.container[1], format='json',
664                                            limit=2, prefix='photos/animals',
665                                            delimiter='/')
666         self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
667         self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
668
669     def test_extended_list_xml(self):
670         xml = self.client.list_objects(self.container[1], format='xml', limit=4,
671                                        prefix='photos', delimiter='/')
672         self.assert_extended(xml, 'xml', 'object', size=4)
673         dirs = xml.getElementsByTagName('subdir')
674         self.assertEqual(len(dirs), 2)
675         self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
676         self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
677
678         objects = xml.getElementsByTagName('name')
679         self.assertEqual(len(objects), 1)
680         self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
681
682     def test_list_meta_double_matching(self):
683         meta = {'quality':'aaa', 'stock':'true'}
684         self.client.update_object_metadata(self.container[0],
685                                            self.obj[0]['name'], **meta)
686         obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
687         self.assertEqual(len(obj), 1)
688         self.assertTrue(obj, self.obj[0]['name'])
689
690     def test_list_using_meta(self):
691         meta = {'quality':'aaa'}
692         for o in self.obj[:2]:
693             self.client.update_object_metadata(self.container[0], o['name'],
694                                                **meta)
695         meta = {'stock':'true'}
696         for o in self.obj[3:5]:
697             self.client.update_object_metadata(self.container[0], o['name'],
698                                                **meta)
699
700         obj = self.client.list_objects(self.container[0], meta='Quality')
701         self.assertEqual(len(obj), 2)
702         self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
703
704         # test case insensitive
705         obj = self.client.list_objects(self.container[0], meta='quality')
706         self.assertEqual(len(obj), 2)
707         self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
708
709         # test multiple matches
710         obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
711         self.assertEqual(len(obj), 4)
712         self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
713
714         # test non 1-1 multiple match
715         obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
716         self.assertEqual(len(obj), 2)
717         self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
718
719     def test_if_modified_since(self):
720         t = datetime.datetime.utcnow()
721         t2 = t - datetime.timedelta(minutes=10)
722
723         #add a new object
724         self.upload_random_data(self.container[0], o_names[0])
725
726         for f in DATE_FORMATS:
727             past = t2.strftime(f)
728             try:
729                 o = self.client.list_objects(self.container[0],
730                                             if_modified_since=past)
731                 self.assertEqual(o,
732                                  self.client.list_objects(self.container[0]))
733             except Fault, f:
734                 self.failIf(f.status == 304) #fail if not modified
735
736     def test_if_modified_since_invalid_date(self):
737         headers = {'if-modified-since':''}
738         o = self.client.list_objects(self.container[0], if_modified_since='')
739         self.assertEqual(o, self.client.list_objects(self.container[0]))
740
741     def test_if_not_modified_since(self):
742         now = datetime.datetime.utcnow()
743         since = now + datetime.timedelta(1)
744
745         for f in DATE_FORMATS:
746             args = {'if_modified_since':'%s' %since.strftime(f)}
747
748             #assert not modified
749             self.assert_raises_fault(304, self.client.list_objects,
750                                      self.container[0], **args)
751
752     def test_if_unmodified_since(self):
753         now = datetime.datetime.utcnow()
754         since = now + datetime.timedelta(1)
755
756         for f in DATE_FORMATS:
757             obj = self.client.list_objects(self.container[0],
758                                            if_unmodified_since=since.strftime(f))
759
760             #assert unmodified
761             self.assertEqual(obj, self.client.list_objects(self.container[0]))
762
763     def test_if_unmodified_since_precondition_failed(self):
764         t = datetime.datetime.utcnow()
765         t2 = t - datetime.timedelta(minutes=10)
766
767         #add a new container
768         self.client.create_container('dummy')
769
770         for f in DATE_FORMATS:
771             past = t2.strftime(f)
772
773             args = {'if_unmodified_since':'%s' %past}
774
775             #assert precondition failed
776             self.assert_raises_fault(412, self.client.list_objects,
777                                      self.container[0], **args)
778
779 class ContainerPut(BaseTestCase):
780     def setUp(self):
781         BaseTestCase.setUp(self)
782         self.containers = ['c1', 'c2']
783
784     def test_create(self):
785         self.client.create_container(self.containers[0])
786         containers = self.client.list_containers()
787         self.assertTrue(self.containers[0] in containers)
788         self.assert_container_exists(self.containers[0])
789
790     def test_create_twice(self):
791         self.client.create_container(self.containers[0])
792         self.assertTrue(not self.client.create_container(self.containers[0]))
793
794     def test_quota(self):
795         self.client.create_container(self.containers[0])
796
797         policy = {'quota':100}
798         self.client.set_container_policies('c1', **policy)
799
800         meta = self.client.retrieve_container_metadata('c1')
801         self.assertTrue('x-container-policy-quota' in meta)
802         self.assertEqual(meta['x-container-policy-quota'], '100')
803
804         args = ['c1', 'o1']
805         kwargs = {'length':101}
806         self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
807
808         #reset quota
809         policy = {'quota':0}
810         self.client.set_container_policies('c1', **policy)
811
812 class ContainerPost(BaseTestCase):
813     def setUp(self):
814         BaseTestCase.setUp(self)
815         self.container = 'apples'
816         self.client.create_container(self.container)
817
818     def test_update_meta(self):
819         meta = {'test':'test33',
820                 'tost':'tost22'}
821         self.client.update_container_metadata(self.container, **meta)
822         headers = self.client.retrieve_container_metadata(self.container)
823         for k,v in meta.items():
824             k = 'x-container-meta-%s' % k
825             self.assertTrue(headers[k])
826             self.assertEqual(headers[k], v)
827
828 class ContainerDelete(BaseTestCase):
829     def setUp(self):
830         BaseTestCase.setUp(self)
831         self.containers = ['c1', 'c2']
832         for c in self.containers:
833             self.client.create_container(c)
834
835     def test_delete(self):
836         status = self.client.delete_container(self.containers[0])[0]
837         self.assertEqual(status, 204)
838
839     def test_delete_non_empty(self):
840         self.upload_random_data(self.containers[1], o_names[0])
841         self.assert_raises_fault(409, self.client.delete_container,
842                                  self.containers[1])
843
844     def test_delete_invalid(self):
845         self.assert_raises_fault(404, self.client.delete_container, 'c3')
846     
847     def test_delete_contents(self):
848         self.client.create_folder(self.containers[0], 'folder-1')
849         self.upload_random_data(self.containers[1], 'folder-1/%s' % o_names[0])
850         self.client.create_folder(self.containers[0], 'folder-1/subfolder')
851         self.client.create_folder(self.containers[0], 'folder-2/%s' % o_names[1])
852                 
853         objects = self.client.list_objects(self.containers[0])
854         self.client.delete_container(self.containers[0], delimiter='/')
855         for o in objects:
856             self.assert_object_not_exists(self.containers[0], o)
857         self.assert_container_exists(self.containers[0])
858
859 class ObjectGet(BaseTestCase):
860     def setUp(self):
861         BaseTestCase.setUp(self)
862         self.containers = ['c1', 'c2']
863         #create some containers
864         for c in self.containers:
865             self.client.create_container(c)
866
867         #upload a file
868         names = ('obj1', 'obj2')
869         self.objects = []
870         for n in names:
871             self.objects.append(self.upload_random_data(self.containers[1], n))
872
873     def test_versions(self):
874         c = self.containers[1]
875         o = self.objects[0]
876         b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
877         self.assert_versionlist_structure(b)
878
879         #update meta
880         meta = {'quality':'AAA', 'stock':True}
881         self.client.update_object_metadata(c, o['name'], **meta)
882
883         a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
884         self.assert_versionlist_structure(a)
885         self.assertEqual(len(b)+1, len(a))
886         self.assertEqual(b, a[:-1])
887
888         #get exact previous version metadata
889         v = a[-2][0]
890         v_meta = self.client.retrieve_object_metadata(c, o['name'],
891                                                       restricted=True,
892                                                       version=v)
893         for k in meta.keys():
894             self.assertTrue(k not in v_meta)
895
896         #update obejct
897         data = get_random_data()
898         self.client.update_object(c, o['name'], StringIO(data))
899
900         aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
901         self.assert_versionlist_structure(aa)
902         self.assertEqual(len(a)+1, len(aa))
903         self.assertEqual(a, aa[:-1])
904
905         #get exact previous version
906         v = aa[-3][0]
907         v_data = self.client.retrieve_object_version(c, o['name'], version=v)
908         self.assertEqual(o['data'], v_data)
909         self.assertEqual(self.client.retrieve_object(c, o['name']),
910                          '%s%s' %(v_data, data))
911
912     def test_get(self):
913         #perform get
914         o = self.client.retrieve_object(self.containers[1],
915                                         self.objects[0]['name'],
916                                         self.objects[0]['meta'])
917         self.assertEqual(o, self.objects[0]['data'])
918
919     def test_objects_with_trailing_spaces(self):
920         self.client.create_container('test')
921         #create 'a' object
922         self.upload_random_data('test', 'a')
923         #look for 'a ' object
924         self.assert_raises_fault(404, self.client.retrieve_object,
925                                  'test', 'a ')
926
927         #delete 'a' object
928         self.client.delete_object('test', 'a')
929         self.assert_raises_fault(404, self.client.retrieve_object,
930                                  'test', 'a')
931
932         #create 'a ' object
933         self.upload_random_data('test', 'a ')
934         #look for 'a' object
935         self.assert_raises_fault(404, self.client.retrieve_object,
936                                  'test', 'a')
937
938     def test_get_invalid(self):
939         self.assert_raises_fault(404, self.client.retrieve_object,
940                                  self.containers[0], self.objects[0]['name'])
941
942     def test_get_partial(self):
943         #perform get with range
944         status, headers, data = self.client.request_object(self.containers[1],
945                                                             self.objects[0]['name'],
946                                                             range='bytes=0-499')
947
948         #assert successful partial content
949         self.assertEqual(status, 206)
950
951         #assert content-type
952         self.assertEqual(headers['content-type'],
953                          self.objects[0]['meta']['content_type'])
954
955         #assert content length
956         self.assertEqual(int(headers['content-length']), 500)
957
958         #assert content
959         self.assertEqual(self.objects[0]['data'][:500], data)
960
961     def test_get_final_500(self):
962         #perform get with range
963         headers = {'range':'bytes=-500'}
964         status, headers, data = self.client.request_object(self.containers[1],
965                                                             self.objects[0]['name'],
966                                                             range='bytes=-500')
967
968         #assert successful partial content
969         self.assertEqual(status, 206)
970
971         #assert content-type
972         self.assertEqual(headers['content-type'],
973                          self.objects[0]['meta']['content_type'])
974
975         #assert content length
976         self.assertEqual(int(headers['content-length']), 500)
977
978         #assert content
979         self.assertTrue(self.objects[0]['data'][-500:], data)
980
981     def test_get_rest(self):
982         #perform get with range
983         offset = len(self.objects[0]['data']) - 500
984         status, headers, data = self.client.request_object(self.containers[1],
985                                                 self.objects[0]['name'],
986                                                 range='bytes=%s-' %offset)
987
988         #assert successful partial content
989         self.assertEqual(status, 206)
990
991         #assert content-type
992         self.assertEqual(headers['content-type'],
993                          self.objects[0]['meta']['content_type'])
994
995         #assert content length
996         self.assertEqual(int(headers['content-length']), 500)
997
998         #assert content
999         self.assertTrue(self.objects[0]['data'][-500:], data)
1000
1001     def test_get_range_not_satisfiable(self):
1002         #perform get with range
1003         offset = len(self.objects[0]['data']) + 1
1004
1005         #assert range not satisfiable
1006         self.assert_raises_fault(416, self.client.retrieve_object,
1007                                  self.containers[1], self.objects[0]['name'],
1008                                  range='bytes=0-%s' %offset)
1009
1010     def test_multiple_range(self):
1011         #perform get with multiple range
1012         ranges = ['0-499', '-500', '1000-']
1013         bytes = 'bytes=%s' % ','.join(ranges)
1014         status, headers, data = self.client.request_object(self.containers[1],
1015                                                            self.objects[0]['name'],
1016                                                            range=bytes)
1017
1018         # assert partial content
1019         self.assertEqual(status, 206)
1020
1021         # assert Content-Type of the reply will be multipart/byteranges
1022         self.assertTrue(headers['content-type'])
1023         content_type_parts = headers['content-type'].split()
1024         self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
1025
1026         boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
1027         cparts = data.split(boundary)[1:-1]
1028
1029         # assert content parts are exactly 2
1030         self.assertEqual(len(cparts), len(ranges))
1031
1032         # for each content part assert headers
1033         i = 0
1034         for cpart in cparts:
1035             content = cpart.split('\r\n')
1036             headers = content[1:3]
1037             content_range = headers[0].split(': ')
1038             self.assertEqual(content_range[0], 'Content-Range')
1039
1040             r = ranges[i].split('-')
1041             if not r[0] and not r[1]:
1042                 pass
1043             elif not r[0]:
1044                 start = len(self.objects[0]['data']) - int(r[1])
1045                 end = len(self.objects[0]['data'])
1046             elif not r[1]:
1047                 start = int(r[0])
1048                 end = len(self.objects[0]['data'])
1049             else:
1050                 start = int(r[0])
1051                 end = int(r[1]) + 1
1052             fdata = self.objects[0]['data'][start:end]
1053             sdata = '\r\n'.join(content[4:-1])
1054             self.assertEqual(len(fdata), len(sdata))
1055             self.assertEquals(fdata, sdata)
1056             i+=1
1057
1058     def test_multiple_range_not_satisfiable(self):
1059         #perform get with multiple range
1060         out_of_range = len(self.objects[0]['data']) + 1
1061         ranges = ['0-499', '-500', '%d-' %out_of_range]
1062         bytes = 'bytes=%s' % ','.join(ranges)
1063
1064         # assert partial content
1065         self.assert_raises_fault(416, self.client.retrieve_object,
1066                                  self.containers[1],
1067                                  self.objects[0]['name'], range=bytes)
1068
1069     def test_get_with_if_match(self):
1070         #perform get with If-Match
1071         etag = self.objects[0]['hash']
1072         status, headers, data = self.client.request_object(self.containers[1],
1073                                                            self.objects[0]['name'],
1074                                                            if_match=etag)
1075         #assert get success
1076         self.assertEqual(status, 200)
1077
1078         #assert content-type
1079         self.assertEqual(headers['content-type'],
1080                          self.objects[0]['meta']['content_type'])
1081
1082         #assert response content
1083         self.assertEqual(self.objects[0]['data'], data)
1084
1085     def test_get_with_if_match_star(self):
1086         #perform get with If-Match *
1087         headers = {'if-match':'*'}
1088         status, headers, data = self.client.request_object(self.containers[1],
1089                                                 self.objects[0]['name'],
1090                                                 **headers)
1091         #assert get success
1092         self.assertEqual(status, 200)
1093
1094         #assert content-type
1095         self.assertEqual(headers['content-type'],
1096                          self.objects[0]['meta']['content_type'])
1097
1098         #assert response content
1099         self.assertEqual(self.objects[0]['data'], data)
1100
1101     def test_get_with_multiple_if_match(self):
1102         #perform get with If-Match
1103         etags = [i['hash'] for i in self.objects if i]
1104         etags = ','.join('"%s"' % etag for etag in etags)
1105         status, headers, data = self.client.request_object(self.containers[1],
1106                                                            self.objects[0]['name'],
1107                                                            if_match=etags)
1108         #assert get success
1109         self.assertEqual(status, 200)
1110
1111         #assert content-type
1112         self.assertEqual(headers['content-type'],
1113                          self.objects[0]['meta']['content_type'])
1114
1115         #assert content-type
1116         self.assertEqual(headers['content-type'],
1117                          self.objects[0]['meta']['content_type'])
1118
1119         #assert response content
1120         self.assertEqual(self.objects[0]['data'], data)
1121
1122     def test_if_match_precondition_failed(self):
1123         #assert precondition failed
1124         self.assert_raises_fault(412, self.client.retrieve_object,
1125                                  self.containers[1],
1126                                  self.objects[0]['name'], if_match='123')
1127
1128     def test_if_none_match(self):
1129         #perform get with If-None-Match
1130         status, headers, data = self.client.request_object(self.containers[1],
1131                                                            self.objects[0]['name'],
1132                                                            if_none_match='123')
1133
1134         #assert get success
1135         self.assertEqual(status, 200)
1136
1137         #assert content-type
1138         self.assertEqual(headers['content_type'],
1139                          self.objects[0]['meta']['content_type'])
1140
1141     def test_if_none_match(self):
1142         #perform get with If-None-Match * and assert not modified
1143         self.assert_raises_fault(304, self.client.retrieve_object,
1144                                  self.containers[1],
1145                                  self.objects[0]['name'],
1146                                  if_none_match='*')
1147
1148     def test_if_none_match_not_modified(self):
1149         #perform get with If-None-Match and assert not modified
1150         self.assert_raises_fault(304, self.client.retrieve_object,
1151                                  self.containers[1],
1152                                  self.objects[0]['name'],
1153                                  if_none_match=self.objects[0]['hash'])
1154
1155         meta = self.client.retrieve_object_metadata(self.containers[1],
1156                                                     self.objects[0]['name'])
1157         self.assertEqual(meta['etag'], self.objects[0]['hash'])
1158
1159     def test_if_modified_since(self):
1160         t = datetime.datetime.utcnow()
1161         t2 = t - datetime.timedelta(minutes=10)
1162
1163         #modify the object
1164         self.upload_data(self.containers[1],
1165                            self.objects[0]['name'],
1166                            self.objects[0]['data'][:200])
1167
1168         for f in DATE_FORMATS:
1169             past = t2.strftime(f)
1170
1171             headers = {'if-modified-since':'%s' %past}
1172             try:
1173                 o = self.client.retrieve_object(self.containers[1],
1174                                                 self.objects[0]['name'],
1175                                                 if_modified_since=past)
1176                 self.assertEqual(o,
1177                                  self.client.retrieve_object(self.containers[1],
1178                                                              self.objects[0]['name']))
1179             except Fault, f:
1180                 self.failIf(f.status == 304)
1181
1182     def test_if_modified_since_invalid_date(self):
1183         o = self.client.retrieve_object(self.containers[1],
1184                                         self.objects[0]['name'],
1185                                         if_modified_since='')
1186         self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1187                                                         self.objects[0]['name']))
1188
1189     def test_if_not_modified_since(self):
1190         now = datetime.datetime.utcnow()
1191         since = now + datetime.timedelta(1)
1192
1193         for f in DATE_FORMATS:
1194             #assert not modified
1195             self.assert_raises_fault(304, self.client.retrieve_object,
1196                                      self.containers[1], self.objects[0]['name'],
1197                                      if_modified_since=since.strftime(f))
1198
1199     def test_if_unmodified_since(self):
1200         now = datetime.datetime.utcnow()
1201         since = now + datetime.timedelta(1)
1202
1203         for f in DATE_FORMATS:
1204             t = since.strftime(f)
1205             status, headers, data = self.client.request_object(self.containers[1],
1206                                                                self.objects[0]['name'],
1207                                                                if_unmodified_since=t)
1208             #assert success
1209             self.assertEqual(status, 200)
1210             self.assertEqual(self.objects[0]['data'], data)
1211
1212             #assert content-type
1213             self.assertEqual(headers['content-type'],
1214                              self.objects[0]['meta']['content_type'])
1215
1216     def test_if_unmodified_since_precondition_failed(self):
1217         t = datetime.datetime.utcnow()
1218         t2 = t - datetime.timedelta(minutes=10)
1219
1220         #modify the object
1221         self.upload_data(self.containers[1],
1222                            self.objects[0]['name'],
1223                            self.objects[0]['data'][:200])
1224
1225         for f in DATE_FORMATS:
1226             past = t2.strftime(f)
1227             #assert precondition failed
1228             self.assert_raises_fault(412, self.client.retrieve_object,
1229                                      self.containers[1], self.objects[0]['name'],
1230                                      if_unmodified_since=past)
1231
1232     def test_hashes(self):
1233         l = 8388609
1234         fname = 'largefile'
1235         o = self.upload_random_data(self.containers[1], fname, l)
1236         if o:
1237             body = self.client.retrieve_object(self.containers[1], fname,
1238                                                format='json')
1239             hashes = body['hashes']
1240             block_size = body['block_size']
1241             block_hash = body['block_hash']
1242             block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1243             self.assertTrue(len(hashes), block_num)
1244             i = 0
1245             for h in hashes:
1246                 start = i * block_size
1247                 end = (i + 1) * block_size
1248                 hash = compute_block_hash(o['data'][start:end], block_hash)
1249                 self.assertEqual(h, hash)
1250                 i += 1
1251
1252 class ObjectPut(BaseTestCase):
1253     def setUp(self):
1254         BaseTestCase.setUp(self)
1255         self.container = 'c1'
1256         self.client.create_container(self.container)
1257
1258     def test_upload(self):
1259         name = o_names[0]
1260         meta = {'test':'test1'}
1261         o = self.upload_random_data(self.container, name, **meta)
1262
1263         headers = self.client.retrieve_object_metadata(self.container,
1264                                                        name,
1265                                                        restricted=True)
1266         self.assertTrue('test' in headers.keys())
1267         self.assertEqual(headers['test'], meta['test'])
1268
1269         #assert uploaded content
1270         status, h, data = self.client.request_object(self.container, name)
1271         self.assertEqual(len(o['data']), int(h['content-length']))
1272         self.assertEqual(o['data'], data)
1273
1274         #assert content-type
1275         self.assertEqual(h['content-type'], o['meta']['content_type'])
1276
1277     def _test_maximum_upload_size_exceeds(self):
1278         name = o_names[0]
1279         meta = {'test':'test1'}
1280         #upload 5GB
1281         length= 5 * (1024 * 1024 * 1024) + 1
1282         self.assert_raises_fault(400, self.upload_random_data, self.container,
1283                                  name, length, **meta)
1284
1285     def test_upload_with_name_containing_slash(self):
1286         name = '/%s' % o_names[0]
1287         meta = {'test':'test1'}
1288         o = self.upload_random_data(self.container, name, **meta)
1289
1290         self.assertEqual(o['data'],
1291                          self.client.retrieve_object(self.container, name))
1292
1293         self.assertTrue(name in self.client.list_objects(self.container))
1294
1295     def test_create_directory_marker(self):
1296         self.client.create_directory_marker(self.container, 'foo')
1297         meta = self.client.retrieve_object_metadata(self.container, 'foo')
1298         self.assertEqual(meta['content-length'], '0')
1299         self.assertEqual(meta['content-type'], 'application/directory')
1300
1301     def test_upload_unprocessable_entity(self):
1302         meta={'etag':'123', 'test':'test1'}
1303
1304         #assert unprocessable entity
1305         self.assert_raises_fault(422, self.upload_random_data, self.container,
1306                                  o_names[0], **meta)
1307
1308     def test_chunked_transfer(self):
1309         data = get_random_data()
1310         objname = 'object'
1311         self.client.create_object_using_chunks(self.container, objname,
1312                                                StringIO(data))
1313
1314         uploaded_data = self.client.retrieve_object(self.container, objname)
1315         self.assertEqual(data, uploaded_data)
1316
1317     def test_manifestation(self):
1318         prefix = 'myobject/'
1319         data = ''
1320         for i in range(5):
1321             part = '%s%d' %(prefix, i)
1322             o = self.upload_random_data(self.container, part)
1323             data += o['data']
1324
1325         manifest = '%s/%s' %(self.container, prefix)
1326         self.client.create_manifestation(self.container, 'large-object', manifest)
1327
1328         self.assert_object_exists(self.container, 'large-object')
1329         self.assertEqual(data, self.client.retrieve_object(self.container,
1330                                                            'large-object'))
1331         
1332         r = self.client.retrieve_object_hashmap(self.container,'large-object')
1333         hashes = r['hashes']
1334         block_size = int(r['block_size'])
1335         block_hash = r['block_hash']
1336         l = len(data)
1337         block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1338         self.assertEqual(block_num, len(hashes))
1339         
1340         #wrong manifestation
1341         self.client.create_manifestation(self.container, 'large-object',
1342                                          '%s/invalid' % self.container)
1343         self.assertEqual('', self.client.retrieve_object(self.container,
1344                                                          'large-object'))
1345
1346     def test_create_zero_length_object(self):
1347         c = self.container
1348         o = 'object'
1349         zero = self.client.create_zero_length_object(c, o)
1350         zero_meta = self.client.retrieve_object_metadata(c, o)
1351         zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1352         zero_data = self.client.retrieve_object(c, o)
1353
1354         self.assertEqual(int(zero_meta['content-length']), 0)
1355         hasher = newhasher('sha256')
1356         hasher.update("")
1357         emptyhash = hasher.digest()
1358         self.assertEqual(zero_hash, [hexlify(emptyhash)])
1359         self.assertEqual(zero_data, '')
1360
1361     def test_create_object_by_hashmap(self):
1362         c = self.container
1363         o = 'object'
1364         self.upload_random_data(c, o)
1365         hashmap = self.client.retrieve_object(c, o, format='json')
1366         o2 = 'object-copy'
1367         self.client.create_object_by_hashmap(c, o2, hashmap)
1368         self.assertEqual(self.client.retrieve_object(c, o),
1369                          self.client.retrieve_object(c, o))
1370
1371 class ObjectCopy(BaseTestCase):
1372     def setUp(self):
1373         BaseTestCase.setUp(self)
1374         self.containers = ['c1', 'c2']
1375         for c in self.containers:
1376             self.client.create_container(c)
1377         self.obj = self.upload_random_data(self.containers[0], o_names[0])
1378
1379     def test_copy(self):
1380         with AssertMappingInvariant(self.client.retrieve_object_metadata,
1381                              self.containers[0], self.obj['name']):
1382             #perform copy
1383             meta = {'test':'testcopy'}
1384             status = self.client.copy_object(self.containers[0],
1385                                               self.obj['name'],
1386                                               self.containers[0],
1387                                               'testcopy',
1388                                               meta)[0]
1389
1390             #assert copy success
1391             self.assertEqual(status, 201)
1392
1393             #assert access the new object
1394             headers = self.client.retrieve_object_metadata(self.containers[0],
1395                                                            'testcopy')
1396             self.assertTrue('x-object-meta-test' in headers.keys())
1397             self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1398
1399             #assert etag is the same
1400             self.assertEqual(headers['etag'], self.obj['hash'])
1401
1402             #assert src object still exists
1403             self.assert_object_exists(self.containers[0], self.obj['name'])
1404
1405     def test_copy_from_different_container(self):
1406         with AssertMappingInvariant(self.client.retrieve_object_metadata,
1407                              self.containers[0], self.obj['name']):
1408             meta = {'test':'testcopy'}
1409             status = self.client.copy_object(self.containers[0],
1410                                              self.obj['name'],
1411                                              self.containers[1],
1412                                              'testcopy',
1413                                              meta)[0]
1414             self.assertEqual(status, 201)
1415
1416             # assert updated metadata
1417             meta = self.client.retrieve_object_metadata(self.containers[1],
1418                                                            'testcopy',
1419                                                            restricted=True)
1420             self.assertTrue('test' in meta.keys())
1421             self.assertTrue(meta['test'], 'testcopy')
1422
1423             #assert src object still exists
1424             self.assert_object_exists(self.containers[0], self.obj['name'])
1425
1426     def test_copy_invalid(self):
1427         #copy from invalid object
1428         meta = {'test':'testcopy'}
1429         self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1430                                  'test.py', self.containers[1], 'testcopy', meta)
1431
1432         #copy from invalid container
1433         meta = {'test':'testcopy'}
1434         self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1435                                  self.obj['name'], self.containers[1],
1436                                  'testcopy', meta)
1437     
1438     def test_copy_dir(self):
1439         self.client.create_folder(self.containers[0], 'dir')
1440         self.client.create_folder(self.containers[0], 'dir/subdir')
1441         self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1442         self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1443         self.client.create_folder(self.containers[0], 'dirs')
1444         
1445         objects = self.client.list_objects(self.containers[0], prefix='dir')
1446         self.client.copy_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/')
1447         for object in objects[:-1]:
1448             self.assert_object_exists(self.containers[0], object)
1449             self.assert_object_exists(self.containers[1], object.replace('dir', 'dir-backup', 1))
1450             meta0 = self.client.retrieve_object_metadata(self.containers[0], object)
1451             meta1 = self.client.retrieve_object_metadata(self.containers[1], object.replace('dir', 'dir-backup', 1))
1452             t = ('content-length', 'x-object-hash', 'content-type')
1453             (self.assertEqual(meta0[elem], meta1[elem]) for elem in t)
1454         self.assert_object_not_exists(self.containers[1], objects[-1])
1455         
1456 class ObjectMove(BaseTestCase):
1457     def setUp(self):
1458         BaseTestCase.setUp(self)
1459         self.containers = ['c1', 'c2']
1460         for c in self.containers:
1461             self.client.create_container(c)
1462         self.obj = self.upload_random_data(self.containers[0], o_names[0])
1463
1464     def test_move(self):
1465         meta = self.client.retrieve_object_metadata(self.containers[0],
1466                                                     self.obj['name'])
1467         self.assertTrue('x-object-uuid' in meta)
1468         uuid = meta['x-object-uuid']
1469
1470         #perform move
1471         meta = {'test':'testcopy'}
1472         src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1473         status = self.client.move_object(self.containers[0], self.obj['name'],
1474                                          self.containers[0], 'testcopy',
1475                                          meta)[0]
1476
1477         #assert successful move
1478         self.assertEqual(status, 201)
1479
1480         #assert updated metadata
1481         meta = self.client.retrieve_object_metadata(self.containers[0],
1482                                                     'testcopy')
1483         self.assertTrue('x-object-meta-test' in meta.keys())
1484         self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1485
1486         #assert same uuid
1487         self.assertTrue(meta['x-object-uuid'], uuid)
1488
1489         #assert src object no more exists
1490         self.assert_object_not_exists(self.containers[0], self.obj['name'])
1491     
1492     
1493     def test_move_dir(self):
1494         meta = {}
1495         self.client.create_folder(self.containers[0], 'dir')
1496         meta['dir'] = self.client.retrieve_object_metadata(self.containers[0], 'dir')
1497         self.client.create_folder(self.containers[0], 'dir/subdir')
1498         meta['dir/subdir'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/subdir')
1499         self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1500         meta['dir/object1.jpg'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/object1.jpg')
1501         self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1502         meta['dir/subdir/object2.pdf'] = self.client.retrieve_object_metadata(self.containers[0], 'dir/subdir/object2.pdf')
1503         self.client.create_folder(self.containers[0], 'dirs')
1504         meta['dirs'] = self.client.retrieve_object_metadata(self.containers[0], 'dirs')
1505         
1506         objects = self.client.list_objects(self.containers[0], prefix='dir')
1507         self.client.move_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/')
1508         for object in objects[:-1]:
1509             self.assert_object_not_exists(self.containers[0], object)
1510             self.assert_object_exists(self.containers[1], object.replace('dir', 'dir-backup', 1))
1511             meta1 = self.client.retrieve_object_metadata(self.containers[1], object.replace('dir', 'dir-backup', 1))
1512             t = ('content-length', 'x-object-hash', 'content-type')
1513             (self.assertEqual(meta0[elem], meta1[elem]) for elem in t)
1514         self.assert_object_exists(self.containers[0], objects[-1])
1515         self.assert_object_not_exists(self.containers[1], objects[-1])
1516
1517 class ObjectPost(BaseTestCase):
1518     def setUp(self):
1519         BaseTestCase.setUp(self)
1520         self.containers = ['c1', 'c2']
1521         for c in self.containers:
1522             self.client.create_container(c)
1523         self.obj = []
1524         for i in range(2):
1525             self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1526
1527     def test_update_meta(self):
1528         with AssertUUidInvariant(self.client.retrieve_object_metadata,
1529                                  self.containers[0],
1530                                  self.obj[0]['name']):
1531             #perform update metadata
1532             more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1533             status = self.client.update_object_metadata(self.containers[0],
1534                                                         self.obj[0]['name'],
1535                                                         **more)[0]
1536             #assert request accepted
1537             self.assertEqual(status, 202)
1538
1539             #assert old metadata are still there
1540             headers = self.client.retrieve_object_metadata(self.containers[0],
1541                                                            self.obj[0]['name'],
1542                                                            restricted=True)
1543             #assert new metadata have been updated
1544             for k,v in more.items():
1545                 self.assertTrue(k in headers.keys())
1546                 self.assertTrue(headers[k], v)
1547
1548             #out of limits
1549             more = {'f' * 114: 'b' * 257}
1550             self.assert_raises_fault(400, self.client.update_object_metadata,
1551                                                         self.containers[0],
1552                                                         self.obj[0]['name'],
1553                                                         **more)
1554             
1555             #perform update metadata
1556             more = {'α': 'β' * 256}
1557             status = self.client.update_object_metadata(self.containers[0],
1558                                                         self.obj[0]['name'],
1559                                                         **more)[0]
1560             #assert request accepted
1561             self.assertEqual(status, 202)
1562             
1563             #assert old metadata are still there
1564             headers = self.client.retrieve_object_metadata(self.containers[0],
1565                                                            self.obj[0]['name'],
1566                                                            restricted=True)
1567             #assert new metadata have been updated
1568             for k,v in more.items():
1569                 self.assertTrue(k in headers.keys())
1570                 self.assertTrue(headers[k], v)
1571             
1572             #out of limits
1573             more = {'α': 'β' * 257}
1574             self.assert_raises_fault(400, self.client.update_object_metadata,
1575                                                         self.containers[0],
1576                                                         self.obj[0]['name'],
1577                                                         **more)
1578     
1579     def test_update_object(self,
1580                            first_byte_pos=0,
1581                            last_byte_pos=499,
1582                            instance_length = True,
1583                            content_length = 500):
1584         with AssertUUidInvariant(self.client.retrieve_object_metadata,
1585                                  self.containers[0],
1586                                  self.obj[0]['name']):
1587             l = len(self.obj[0]['data'])
1588             range = 'bytes %d-%d/%s' %(first_byte_pos,
1589                                            last_byte_pos,
1590                                             l if instance_length else '*')
1591             partial = last_byte_pos - first_byte_pos + 1
1592             length = first_byte_pos + partial
1593             data = get_random_data(partial)
1594             args = {'content_type':'application/octet-stream',
1595                     'content_range':'%s' %range}
1596             if content_length:
1597                 args['content_length'] = content_length
1598
1599             r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1600                                       StringIO(data), **args)
1601             status = r[0]
1602             etag = r[1]['etag']
1603             if partial < 0 or (instance_length and l <= last_byte_pos):
1604                 self.assertEqual(status, 202)
1605             else:
1606                 self.assertEqual(status, 204)
1607                 #check modified object
1608                 content = self.client.retrieve_object(self.containers[0],
1609                                                   self.obj[0]['name'])
1610                 self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1611                 self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1612                 self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1613                 self.assertEqual(etag, compute_md5_hash(content))
1614
1615     def test_update_object_lt_blocksize(self):
1616         self.test_update_object(10, 20, content_length=None)
1617
1618     def test_update_object_gt_blocksize(self):
1619         o = self.upload_random_data(self.containers[0], o_names[1],
1620                                 length=4*1024*1024+5)
1621         c = self.containers[0]
1622         o_name = o['name']
1623         o_data = o['data']
1624         first_byte_pos = 4*1024*1024+1
1625         last_byte_pos = 4*1024*1024+4
1626         l = last_byte_pos - first_byte_pos + 1
1627         data = get_random_data(l)
1628         range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1629         self.client.update_object(c, o_name, StringIO(data), content_range=range)
1630         content = self.client.retrieve_object(c, o_name)
1631         self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1632         self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1633         self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1634
1635     def test_update_object_divided_by_blocksize(self):
1636         o = self.upload_random_data(self.containers[0], o_names[1],
1637                                 length=4*1024*1024+5)
1638         c = self.containers[0]
1639         o_name = o['name']
1640         o_data = o['data']
1641         first_byte_pos = 4*1024*1024
1642         last_byte_pos = 5*1024*1024
1643         l = last_byte_pos - first_byte_pos + 1
1644         data = get_random_data(l)
1645         range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1646         self.client.update_object(c, o_name, StringIO(data), content_range=range)
1647         content = self.client.retrieve_object(c, o_name)
1648         self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1649         self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1650         self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1651
1652     def test_update_object_no_content_length(self):
1653         self.test_update_object(content_length = None)
1654
1655     def test_update_object_invalid_content_length(self):
1656         with AssertContentInvariant(self.client.retrieve_object,
1657                                     self.containers[0], self.obj[0]['name']):
1658             self.assert_raises_fault(400, self.test_update_object,
1659                                      content_length = 1000)
1660
1661     def test_update_object_invalid_range(self):
1662         with AssertContentInvariant(self.client.retrieve_object,
1663                                     self.containers[0], self.obj[0]['name']):
1664             self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1665
1666     def test_update_object_invalid_range_and_length(self):
1667         with AssertContentInvariant(self.client.retrieve_object,
1668                                     self.containers[0], self.obj[0]['name']):
1669             self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1670                                      -1)
1671
1672     def test_update_object_invalid_range_with_no_content_length(self):
1673         with AssertContentInvariant(self.client.retrieve_object,
1674                                     self.containers[0], self.obj[0]['name']):
1675             self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1676                                      content_length = None)
1677
1678     def test_update_object_out_of_limits(self):
1679         with AssertContentInvariant(self.client.retrieve_object,
1680                                     self.containers[0], self.obj[0]['name']):
1681             l = len(self.obj[0]['data'])
1682             self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1683
1684     def test_append(self):
1685         data = get_random_data(500)
1686         headers = {}
1687         self.client.update_object(self.containers[0], self.obj[0]['name'],
1688                                   StringIO(data), content_length=500,
1689                                   content_type='application/octet-stream')
1690
1691         content = self.client.retrieve_object(self.containers[0],
1692                                               self.obj[0]['name'])
1693         self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1694         self.assertEqual(content[:-500], self.obj[0]['data'])
1695
1696     def test_update_with_chunked_transfer(self):
1697         data = get_random_data(500)
1698         dl = len(data)
1699         fl = len(self.obj[0]['data'])
1700
1701         self.client.update_object_using_chunks(self.containers[0],
1702                                                self.obj[0]['name'],
1703                                                StringIO(data),
1704                                                offset=0,
1705                                                content_type='application/octet-stream')
1706
1707         #check modified object
1708         content = self.client.retrieve_object(self.containers[0],
1709                                               self.obj[0]['name'])
1710         self.assertEqual(content[0:dl], data)
1711         self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1712
1713     def test_update_from_other_object(self):
1714         c = self.containers[0]
1715         src = o_names[0]
1716         dest = 'object'
1717
1718         source_data = self.client.retrieve_object(c, src)
1719         source_meta = self.client.retrieve_object_metadata(c, src)
1720         source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1721
1722         #update zero length object
1723         self.client.create_zero_length_object(c, dest)
1724         source_object = '/%s/%s' % (c, src)
1725         self.client.update_from_other_source(c, dest, source_object)
1726         dest_data = self.client.retrieve_object(c, src)
1727         dest_meta = self.client.retrieve_object_metadata(c, dest)
1728         dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1729         self.assertEqual(source_data, dest_data)
1730         self.assertEqual(source_hash, dest_hash)
1731
1732         #test append
1733         self.client.update_from_other_source(c, dest, source_object)
1734         content = self.client.retrieve_object(c, dest)
1735         self.assertEqual(source_data * 2, content)
1736
1737     def test_update_range_from_other_object(self):
1738         c = self.containers[0]
1739         dest = 'object'
1740
1741         #test update range
1742         src = self.obj[1]['name']
1743         src_data = self.client.retrieve_object(c, src)
1744
1745         #update zero length object
1746         prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1747         source_object = '/%s/%s' % (c, src)
1748         first_byte_pos = 4*1024*1024+1
1749         last_byte_pos = 4*1024*1024+4
1750         range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1751         self.client.update_from_other_source(c, dest, source_object,
1752                                              content_range=range)
1753         content = self.client.retrieve_object(c, dest)
1754         self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1755         self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1756         self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1757
1758     def test_update_hashes_from_other_object(self):
1759         c = self.containers[0]
1760         dest = 'object'
1761
1762         #test update range
1763         src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1764
1765         #update zero length object
1766         prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1767         source_object = '/%s/%s' % (c, o_names[0])
1768         first_byte_pos = 4*1024*1024
1769         last_byte_pos = 5*1024*1024
1770         range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1771         self.client.update_from_other_source(c, dest, source_object,
1772                                              content_range=range)
1773         content = self.client.retrieve_object(c, dest)
1774         self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1775         self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1776         self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1777
1778
1779     def test_update_zero_length_object(self):
1780         c = self.containers[0]
1781         o = 'object'
1782         other = 'other'
1783         zero = self.client.create_zero_length_object(c, o)
1784
1785         data = get_random_data()
1786         self.client.update_object(c, o, StringIO(data))
1787         self.client.create_object(c, other, StringIO(data))
1788
1789         self.assertEqual(self.client.retrieve_object(c, o),
1790                          self.client.retrieve_object(c, other))
1791
1792         self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1793                          self.client.retrieve_object_hashmap(c, other)["hashes"])
1794
1795 class ObjectDelete(BaseTestCase):
1796     def setUp(self):
1797         BaseTestCase.setUp(self)
1798         self.containers = ['c1', 'c2']
1799         for c in self.containers:
1800             self.client.create_container(c)
1801         self.obj = self.upload_random_data(self.containers[0], o_names[0])
1802
1803     def test_delete(self):
1804         #perform delete object
1805         self.client.delete_object(self.containers[0], self.obj['name'])[0]
1806
1807     def test_delete_invalid(self):
1808         #assert item not found
1809         self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1810                                  self.obj['name'])
1811     
1812     def test_delete_dir(self):
1813         self.client.create_folder(self.containers[0], 'dir')
1814         self.client.create_folder(self.containers[0], 'dir/subdir')
1815         self.upload_random_data(self.containers[0], 'dir/object1.jpg', length=1024)
1816         self.upload_random_data(self.containers[0], 'dir/subdir/object2.pdf', length=2*1024)
1817         self.client.create_folder(self.containers[0], 'dirs')
1818         
1819         objects = self.client.list_objects(self.containers[0], prefix='dir')
1820         self.client.delete_object(self.containers[0], 'dir', delimiter='/')
1821         for object in objects[:-1]:
1822             self.assert_object_not_exists(self.containers[0], object)
1823         self.assert_object_exists(self.containers[0], objects[-1])
1824
1825 class ListSharing(BaseTestCase):
1826     def setUp(self):
1827         BaseTestCase.setUp(self)
1828         for i in range(2):
1829             self.client.create_container('c%s' %i)
1830         self.client.create_container('c')
1831         for i in range(2):
1832             self.upload_random_data('c1', 'o%s' %i)
1833         accounts = OTHER_ACCOUNTS.copy()
1834         self.o1_sharing_with = accounts.popitem()
1835         self.o1_sharing = [self.o1_sharing_with[1]]
1836         self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1837
1838         l = []
1839         for i in range(2):
1840             l.append(accounts.popitem())
1841
1842     def test_list_other_shared(self):
1843         self.other = Pithos_Client(get_url(),
1844                               self.o1_sharing_with[0],
1845                               self.o1_sharing_with[1])
1846         self.assertTrue(get_user() in self.other.list_shared_by_others())
1847
1848     def test_list_my_shared(self):
1849         my_shared_containers = self.client.list_containers(shared=True)
1850         self.assertTrue('c1' in my_shared_containers)
1851         self.assertTrue('c2' not in my_shared_containers)
1852
1853         my_shared_objects = self.client.list_objects('c1', shared=True)
1854         self.assertTrue('o1' in my_shared_objects)
1855         self.assertTrue('o2' not in my_shared_objects)
1856
1857 class List(BaseTestCase):
1858     def setUp(self):
1859         BaseTestCase.setUp(self)
1860         for i in range(1, 5):
1861             c = 'c%s' % i
1862             self.client.create_container(c)
1863             for j in range(1, 3):
1864                 o = 'o%s' % j
1865                 self.upload_random_data(c, o)
1866             if i < 3:
1867                 self.client.share_object(c, 'o1', ['papagian'], read=True)
1868             if i%2 != 0:
1869                 self.client.publish_object(c, 'o2')
1870     
1871     def test_shared_public(self):
1872         func, kwargs = self.client.list_containers, {'shared':True}
1873         l = func(**kwargs)
1874         self.assertEqual(l, ['c1', 'c2'])
1875         self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1876         
1877         func, kwargs = self.client.list_containers, {'public':True}
1878         l = func(**kwargs)
1879         self.assertEqual(l, ['c1', 'c3'])
1880         self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1881         
1882         func, kwargs = self.client.list_containers, {'shared':True, 'public':True}
1883         l = func(**kwargs)
1884         self.assertEqual(l, ['c1', 'c2', 'c3'])
1885         self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1886         
1887         
1888         func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True}
1889         l = func(*args, **kwargs)
1890         self.assertEqual(l, ['o1'])
1891         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1892         
1893         func, args, kwargs = self.client.list_objects, ['c1'], {'public':True}
1894         l = func(*args, **kwargs)
1895         self.assertEqual(l, ['o2'])
1896         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1897         
1898         func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True, 'public':True}
1899         l = func(*args, **kwargs)
1900         self.assertEqual(l, ['o1', 'o2'])
1901         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1902         
1903         
1904         func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True}
1905         l = func(*args, **kwargs)
1906         self.assertEqual(l, ['o1'])
1907         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1908         
1909         func, args, kwargs = self.client.list_objects, ['c2'], {'public':True}
1910         l = func(*args, **kwargs)
1911         self.assertEqual(l, '')
1912         self.assertEqual([], func(*args, format='json', **kwargs))
1913         
1914         func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True, 'public':True}
1915         l = func(*args, **kwargs)
1916         self.assertEqual(l, ['o1'])
1917         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1918         
1919         
1920         func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True}
1921         l = func(*args, **kwargs)
1922         self.assertEqual(l, '')
1923         self.assertEqual([], func(*args, format='json', **kwargs))
1924         
1925         func, args, kwargs = self.client.list_objects, ['c3'], {'public':True}
1926         l = func(*args, **kwargs)
1927         self.assertEqual(l, ['o2'])
1928         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1929         
1930         func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True, 'public':True}
1931         l = func(*args, **kwargs)
1932         self.assertEqual(l, ['o2'])
1933         self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1934         
1935         
1936         func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True}
1937         l = func(*args, **kwargs)
1938         self.assertEqual(l, '')
1939         self.assertEqual([], func(*args, format='json', **kwargs))
1940         
1941         func, args, kwargs = self.client.list_objects, ['c4'], {'public':True}
1942         l = func(*args, **kwargs)
1943         self.assertEqual(l, '')
1944         self.assertEqual([], func(*args, format='json', **kwargs))
1945         
1946         func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True, 'public':True}
1947         l = func(*args, **kwargs)
1948         self.assertEqual(l, '')
1949         self.assertEqual([], func(*args, format='json', **kwargs))
1950
1951 class TestGreek(BaseTestCase):
1952     def test_create_container(self):
1953         self.client.create_container('φάκελος')
1954         self.assert_container_exists('φάκελος')
1955
1956         self.assertTrue('φάκελος' in self.client.list_containers())
1957
1958     def test_create_object(self):
1959         self.client.create_container('φάκελος')
1960         self.upload_random_data('φάκελος', 'αντικείμενο')
1961
1962         self.assert_object_exists('φάκελος', 'αντικείμενο')
1963         self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1964
1965     def test_copy_object(self):
1966         src_container = 'φάκελος'
1967         src_object = 'αντικείμενο'
1968         dest_container = 'αντίγραφα'
1969         dest_object = 'ασφαλές-αντίγραφο'
1970
1971         self.client.create_container(src_container)
1972         self.upload_random_data(src_container, src_object)
1973
1974         self.client.create_container(dest_container)
1975         self.client.copy_object(src_container, src_object, dest_container,
1976                                 dest_object)
1977
1978         self.assert_object_exists(src_container, src_object)
1979         self.assert_object_exists(dest_container, dest_object)
1980         self.assertTrue(dest_object in self.client.list_objects(dest_container))
1981
1982     def test_move_object(self):
1983         src_container = 'φάκελος'
1984         src_object = 'αντικείμενο'
1985         dest_container = 'αντίγραφα'
1986         dest_object = 'ασφαλές-αντίγραφο'
1987
1988         self.client.create_container(src_container)
1989         self.upload_random_data(src_container, src_object)
1990
1991         self.client.create_container(dest_container)
1992         self.client.move_object(src_container, src_object, dest_container,
1993                                 dest_object)
1994
1995         self.assert_object_not_exists(src_container, src_object)
1996         self.assert_object_exists(dest_container, dest_object)
1997         self.assertTrue(dest_object in self.client.list_objects(dest_container))
1998
1999     def test_delete_object(self):
2000         self.client.create_container('φάκελος')
2001         self.upload_random_data('φάκελος', 'αντικείμενο')
2002         self.assert_object_exists('φάκελος', 'αντικείμενο')
2003
2004         self.client.delete_object('φάκελος', 'αντικείμενο')
2005         self.assert_object_not_exists('φάκελος', 'αντικείμενο')
2006         self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
2007
2008     def test_delete_container(self):
2009         self.client.create_container('φάκελος')
2010         self.assert_container_exists('φάκελος')
2011
2012         self.client.delete_container('φάκελος')
2013         self.assert_container_not_exists('φάκελος')
2014         self.assertTrue('φάκελος' not in self.client.list_containers())
2015
2016     def test_account_meta(self):
2017         meta = {'ποιότητα':'ΑΑΑ'}
2018         self.client.update_account_metadata(**meta)
2019         meta = self.client.retrieve_account_metadata(restricted=True)
2020         self.assertTrue('ποιότητα' in meta.keys())
2021         self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2022
2023     def test_container_meta(self):
2024         meta = {'ποιότητα':'ΑΑΑ'}
2025         self.client.create_container('φάκελος', meta=meta)
2026
2027         meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
2028         self.assertTrue('ποιότητα' in meta.keys())
2029         self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2030
2031     def test_object_meta(self):
2032         self.client.create_container('φάκελος')
2033         meta = {'ποιότητα':'ΑΑΑ'}
2034         self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
2035
2036         meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
2037                                                     restricted=True)
2038         self.assertTrue('ποιότητα' in meta.keys())
2039         self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2040
2041     def test_list_meta_filtering(self):
2042         self.client.create_container('φάκελος')
2043         meta = {'ποιότητα':'ΑΑΑ'}
2044         self.upload_random_data('φάκελος', 'ο1', **meta)
2045         self.upload_random_data('φάκελος', 'ο2')
2046         self.upload_random_data('φάκελος', 'ο3')
2047
2048         meta = {'ποσότητα':'μεγάλη'}
2049         self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2050         objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
2051         self.assertEquals(objects, ['ο1', 'ο2'])
2052
2053         objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
2054         self.assertEquals(objects, ['ο2', 'ο3'])
2055
2056         objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
2057         self.assertEquals(objects, ['ο3'])
2058
2059         meta = {'ποιότητα':'ΑΒ'}
2060         self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2061         objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
2062         self.assertEquals(objects, ['ο1'])
2063         objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
2064         self.assertEquals(objects, ['ο2'])
2065
2066         meta = {'έτος':'2011'}
2067         self.client.update_object_metadata('φάκελος', 'ο3', **meta)
2068         meta = {'έτος':'2012'}
2069         self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2070         objects = self.client.list_objects('φάκελος', meta='έτος<2012')
2071         self.assertEquals(objects, ['ο3'])
2072         objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
2073         self.assertEquals(objects, ['ο2', 'ο3'])
2074         objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
2075         self.assertEquals(objects, '')
2076
2077     def test_groups(self):
2078         #create a group
2079         groups = {'σεφς':'chazapis,διογένης'}
2080         self.client.set_account_groups(**groups)
2081         groups.update(self.initial_groups)
2082         self.assertEqual(groups['σεφς'],
2083                          self.client.retrieve_account_groups()['σεφς'])
2084
2085         #check read access
2086         self.client.create_container('φάκελος')
2087         o = self.upload_random_data('φάκελος', 'ο1')
2088         self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
2089         chef = Pithos_Client(get_url(),
2090                             '0009',
2091                             'διογένης')
2092         self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
2093                                      'φάκελος', 'ο1', account=get_user())
2094
2095         #check write access
2096         self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
2097         new_data = get_random_data()
2098         self.assert_not_raises_fault(403, chef.update_object,
2099                                      'φάκελος', 'ο1', StringIO(new_data),
2100                                      account=get_user())
2101
2102         server_data = self.client.retrieve_object('φάκελος', 'ο1')
2103         self.assertEqual(server_data[:len(o['data'])], o['data'])
2104         self.assertEqual(server_data[len(o['data']):], new_data)
2105
2106     def test_manifestation(self):
2107         self.client.create_container('κουβάς')
2108         prefix = 'μέρη/'
2109         data = ''
2110         for i in range(5):
2111             part = '%s%d' %(prefix, i)
2112             o = self.upload_random_data('κουβάς', part)
2113             data += o['data']
2114
2115         self.client.create_container('φάκελος')
2116         manifest = '%s/%s' %('κουβάς', prefix)
2117         self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
2118
2119         self.assert_object_exists('φάκελος', 'άπαντα')
2120         self.assertEqual(data, self.client.retrieve_object('φάκελος',
2121                                                            'άπαντα'))
2122
2123         #wrong manifestation
2124         self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
2125         self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
2126
2127     def test_update_from_another_object(self):
2128         self.client.create_container('κουβάς')
2129         src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
2130         initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
2131         source_object = '/%s/%s' % ('κουβάς', 'πηγή')
2132         self.client.update_from_other_source('κουβάς', 'νέο', source_object)
2133
2134         self.assertEqual(
2135             self.client.retrieve_object('κουβάς', 'νέο'),
2136             '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
2137
2138 class TestPermissions(BaseTestCase):
2139     def setUp(self):
2140         BaseTestCase.setUp(self)
2141
2142         #create a group
2143         self.authorized = ['chazapis', 'verigak', 'gtsouk']
2144         groups = {'pithosdev':','.join(self.authorized)}
2145         self.client.set_account_groups(**groups)
2146
2147         self.container = 'c'
2148         self.object = 'o'
2149         self.client.create_container(self.container)
2150         self.upload_random_data(self.container, self.object)
2151         self.upload_random_data(self.container, self.object+'/')
2152         self.upload_random_data(self.container, self.object+'/a')
2153         self.upload_random_data(self.container, self.object+'a')
2154         self.upload_random_data(self.container, self.object+'a/')
2155         self.dir_content_types = ('application/directory', 'application/folder')
2156
2157     def assert_read(self, authorized=[], any=False, depth=0):
2158         for token, account in OTHER_ACCOUNTS.items():
2159             cl = Pithos_Client(get_url(), token, account)
2160             if account in authorized or any:
2161                 self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2162                                              self.container, self.object,
2163                                              account=get_user())
2164             else:
2165                 self.assert_raises_fault(403, cl.retrieve_object_metadata,
2166                                          self.container, self.object,
2167                                          account=get_user())
2168
2169         #check inheritance
2170         meta = self.client.retrieve_object_metadata(self.container, self.object)
2171         type = meta['content-type']
2172         derivatives = self.client.list_objects(self.container, prefix=self.object)
2173         #exclude the self.object
2174         del derivatives[derivatives.index(self.object)]
2175         for o in derivatives:
2176             for token, account in OTHER_ACCOUNTS.items():
2177                 cl = Pithos_Client(get_url(), token, account)
2178                 prefix = self.object if self.object.endswith('/') else self.object+'/'
2179                 if (account in authorized or any) and \
2180                 (type in self.dir_content_types) and \
2181                 o.startswith(prefix):
2182                     self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2183                                              self.container, o, account=get_user())
2184                 else:
2185                     self.assert_raises_fault(403, cl.retrieve_object_metadata,
2186                                          self.container, o, account=get_user())
2187
2188     def assert_write(self, authorized=[], any=False):
2189         o_data = self.client.retrieve_object(self.container, self.object)
2190         for token, account in OTHER_ACCOUNTS.items():
2191             cl = Pithos_Client(get_url(), token, account)
2192             new_data = get_random_data()
2193             if account in authorized or any:
2194                 # test write access
2195                 self.assert_not_raises_fault(403, cl.update_object,
2196                                              self.container, self.object, StringIO(new_data),
2197                                              account=get_user())
2198                 try:
2199                     # test read access
2200                     server_data = cl.retrieve_object(self.container, self.object, account=get_user())
2201                     self.assertEqual(o_data, server_data[:len(o_data)])
2202                     self.assertEqual(new_data, server_data[len(o_data):])
2203                     o_data = server_data
2204                 except Fault, f:
2205                     self.failIf(f.status == 403)
2206             else:
2207                 self.assert_raises_fault(403, cl.update_object,
2208                                              self.container, self.object, StringIO(new_data),
2209                                              account=get_user())
2210         #check inheritance
2211         meta = self.client.retrieve_object_metadata(self.container, self.object)
2212         type = meta['content-type']
2213         derivatives = self.client.list_objects(self.container, prefix=self.object)
2214         #exclude the object
2215         del derivatives[derivatives.index(self.object)]
2216         for o in derivatives:
2217             for token, account in OTHER_ACCOUNTS.items():
2218                 prefix = self.object if self.object.endswith('/') else self.object+'/'
2219                 cl = Pithos_Client(get_url(), token, account)
2220                 new_data = get_random_data()
2221                 if (account in authorized or any) and \
2222                 (type in self.dir_content_types) and \
2223                 o.startswith(prefix):
2224                     # test write access
2225                     self.assert_not_raises_fault(403, cl.update_object,
2226                                                  self.container, o,
2227                                                  StringIO(new_data),
2228                                                  account=get_user())
2229                     try:
2230                         server_data = cl.retrieve_object(self.container, o, account=get_user())
2231                         self.assertEqual(new_data, server_data[-len(new_data):])
2232                     except Fault, f:
2233                         self.failIf(f.status == 403)
2234                 else:
2235                     self.assert_raises_fault(403, cl.update_object,
2236                                                  self.container, o,
2237                                                  StringIO(new_data),
2238                                                  account=get_user())
2239
2240     def test_group_read(self):
2241         self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2242         self.assert_read(authorized=self.authorized)
2243
2244     def test_read_many(self):
2245         self.client.share_object(self.container, self.object, self.authorized)
2246         self.assert_read(authorized=self.authorized)
2247
2248     def test_read_by_everyone(self):
2249         self.client.share_object(self.container, self.object, ['*'])
2250         self.assert_read(any=True)
2251
2252     def test_read_directory(self):
2253         for type in self.dir_content_types:
2254             #change content type
2255             self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2256             self.client.share_object(self.container, self.object, ['*'])
2257             self.assert_read(any=True)
2258             self.client.share_object(self.container, self.object, self.authorized)
2259             self.assert_read(authorized=self.authorized)
2260             self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2261             self.assert_read(authorized=self.authorized)
2262
2263     def test_group_write(self):
2264         self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2265         self.assert_write(authorized=self.authorized)
2266
2267     def test_write_many(self):
2268         self.client.share_object(self.container, self.object, self.authorized, read=False)
2269         self.assert_write(authorized=self.authorized)
2270
2271     def test_write_by_everyone(self):
2272         self.client.share_object(self.container, self.object, ['*'], read=False)
2273         self.assert_write(any=True)
2274
2275     def test_write_directory(self):
2276         dir_content_types = ('application/directory', 'application/foler')
2277         for type in dir_content_types:
2278             #change content type
2279             self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2280             self.client.share_object(self.container, self.object, ['*'], read=False)
2281             self.assert_write(any=True)
2282             self.client.share_object(self.container, self.object, self.authorized, read=False)
2283             self.assert_write(authorized=self.authorized)
2284             self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2285             self.assert_write(authorized=self.authorized)
2286
2287     def test_shared_listing(self):
2288         self.client.share_object(self.container, self.object, self.authorized)
2289
2290         my_shared_containers = self.client.list_containers(shared=True)
2291         self.assertEqual(['c'], my_shared_containers)
2292         my_shared_objects = self.client.list_objects('c', shared=True)
2293         self.assertEqual(['o'], my_shared_objects)
2294
2295         dir_content_types = ('application/directory', 'application/foler')
2296         for type in dir_content_types:
2297             #change content type
2298             self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2299             my_shared_objects = self.client.list_objects('c', shared=True)
2300             self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2301
2302         for token, account in OTHER_ACCOUNTS.items():
2303             if account in self.authorized:
2304                 self.other = Pithos_Client(get_url(), token, account)
2305                 self.assertTrue(get_user() in self.other.list_shared_by_others())
2306
2307 class TestPublish(BaseTestCase):
2308     def test_publish(self):
2309         self.client.create_container('c')
2310         o_data = self.upload_random_data('c', 'o')['data']
2311         self.client.publish_object('c', 'o')
2312         meta = self.client.retrieve_object_metadata('c', 'o')
2313         self.assertTrue('x-object-public' in meta)
2314         url = meta['x-object-public']
2315
2316         p = urlparse(get_url())
2317         if p.scheme == 'http':
2318             conn = HTTPConnection(p.netloc)
2319         elif p.scheme == 'https':
2320             conn = HTTPSConnection(p.netloc)
2321         else:
2322             raise Exception('Unknown URL scheme')
2323
2324         conn.request('GET', url)
2325         resp = conn.getresponse()
2326         length = resp.getheader('content-length', None)
2327         data = resp.read(length)
2328         self.assertEqual(o_data, data)
2329
2330 class TestPolicies(BaseTestCase):
2331     def test_none_versioning(self):
2332         self.client.create_container('c', policies={'versioning':'none'})
2333         o = self.upload_random_data('c', 'o')
2334         meta = self.client.retrieve_object_metadata('c', 'o')
2335         v = meta['x-object-version']
2336         more_data = get_random_data()
2337         self.client.update_object('c', 'o', StringIO(more_data))
2338         vlist = self.client.retrieve_object_versionlist('c', 'o')
2339         self.assert_raises_fault(404, self.client.retrieve_object_version,
2340                                  'c', 'o', v)
2341         data = self.client.retrieve_object('c', 'o')
2342         end = len(o['data'])
2343         self.assertEqual(data[:end], o['data'])
2344         self.assertEqual(data[end:], more_data)
2345
2346     def test_quota(self):
2347         self.client.create_container('c', policies={'quota':'1'})
2348         meta = self.client.retrieve_container_metadata('c')
2349         self.assertEqual(meta['x-container-policy-quota'], '1')
2350         self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2351                                  length=1024*1024+1)
2352
2353     def test_quota_none(self):
2354         self.client.create_container('c', policies={'quota':'0'})
2355         meta = self.client.retrieve_container_metadata('c')
2356         self.assertEqual(meta['x-container-policy-quota'], '0')
2357         self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2358                                  length=1024*1024+1)
2359
2360 class AssertUUidInvariant(object):
2361     def __init__(self, callable, *args, **kwargs):
2362         self.callable = callable
2363         self.args = args
2364         self.kwargs = kwargs
2365
2366     def __enter__(self):
2367         self.map = self.callable(*self.args, **self.kwargs)
2368         assert('x-object-uuid' in self.map)
2369         self.uuid = self.map['x-object-uuid']
2370         return self.map
2371
2372     def __exit__(self, type, value, tb):
2373         map = self.callable(*self.args, **self.kwargs)
2374         assert('x-object-uuid' in self.map)
2375         uuid = map['x-object-uuid']
2376         assert(uuid == self.uuid)
2377
2378 class AssertMappingInvariant(object):
2379     def __init__(self, callable, *args, **kwargs):
2380         self.callable = callable
2381         self.args = args
2382         self.kwargs = kwargs
2383
2384     def __enter__(self):
2385         self.map = self.callable(*self.args, **self.kwargs)
2386         return self.map
2387
2388     def __exit__(self, type, value, tb):
2389         map = self.callable(*self.args, **self.kwargs)
2390         for k, v in self.map.items():
2391             if is_date(v):
2392                 continue
2393             assert(k in map)
2394             assert v == map[k]
2395
2396 class AssertContentInvariant(object):
2397     def __init__(self, callable, *args, **kwargs):
2398         self.callable = callable
2399         self.args = args
2400         self.kwargs = kwargs
2401
2402     def __enter__(self):
2403         self.content = self.callable(*self.args, **self.kwargs)[2]
2404         return self.content
2405
2406     def __exit__(self, type, value, tb):
2407         content = self.callable(*self.args, **self.kwargs)[2]
2408         assert self.content == content
2409
2410 def get_content_splitted(response):
2411     if response:
2412         return response.content.split('\n')
2413
2414 def compute_md5_hash(data):
2415     md5 = hashlib.md5()
2416     offset = 0
2417     md5.update(data)
2418     return md5.hexdigest().lower()
2419
2420 def compute_block_hash(data, algorithm):
2421     h = hashlib.new(algorithm)
2422     h.update(data.rstrip('\x00'))
2423     return h.hexdigest()
2424
2425 def get_random_data(length=500):
2426     char_set = string.ascii_uppercase + string.digits
2427     return ''.join(random.choice(char_set) for x in xrange(length))
2428
2429 def is_date(date):
2430     MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2431     __D = r'(?P<day>\d{2})'
2432     __D2 = r'(?P<day>[ \d]\d)'
2433     __M = r'(?P<mon>\w{3})'
2434     __Y = r'(?P<year>\d{4})'
2435     __Y2 = r'(?P<year>\d{2})'
2436     __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2437     RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2438     RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2439     ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2440     for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2441         m = regex.match(date)
2442         if m is not None:
2443             return True
2444     return False
2445
2446 def strnextling(prefix):
2447     """Return the first unicode string
2448        greater than but not starting with given prefix.
2449        strnextling('hello') -> 'hellp'
2450     """
2451     if not prefix:
2452         ## all strings start with the null string,
2453         ## therefore we have to approximate strnextling('')
2454         ## with the last unicode character supported by python
2455         ## 0x10ffff for wide (32-bit unicode) python builds
2456         ## 0x00ffff for narrow (16-bit unicode) python builds
2457         ## We will not autodetect. 0xffff is safe enough.
2458         return unichr(0xffff)
2459     s = prefix[:-1]
2460     c = ord(prefix[-1])
2461     if c >= 0xffff:
2462         raise RuntimeError
2463     s += unichr(c+1)
2464     return s
2465
2466 o_names = ['kate.jpg',
2467            'kate_beckinsale.jpg',
2468            'How To Win Friends And Influence People.pdf',
2469            'moms_birthday.jpg',
2470            'poodle_strut.mov',
2471            'Disturbed - Down With The Sickness.mp3',
2472            'army_of_darkness.avi',
2473            'the_mad.avi',
2474            'photos/animals/dogs/poodle.jpg',
2475            'photos/animals/dogs/terrier.jpg',
2476            'photos/animals/cats/persian.jpg',
2477            'photos/animals/cats/siamese.jpg',
2478            'photos/plants/fern.jpg',
2479            'photos/plants/rose.jpg',
2480            'photos/me.jpg']
2481
2482
2483 def main():
2484     if get_user() == 'test':
2485         unittest.main(module='pithos.tools.test')
2486     else:
2487         print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2488
2489
2490 if __name__ == "__main__":
2491     main()
2492