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