Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-tools / pithos / tools / test.py @ e53e90da

History | View | Annotate | Download (96.2 kB)

1
#!/usr/bin/env python
2
#coding=utf8
3

    
4
# Copyright 2011-2012 GRNET S.A. All rights reserved.
5
#
6
# Redistribution and use in source and binary forms, with or
7
# without modification, are permitted provided that the following
8
# conditions are met:
9
#
10
#   1. Redistributions of source code must retain the above
11
#      copyright notice, this list of conditions and the following
12
#      disclaimer.
13
#
14
#   2. Redistributions in binary form must reproduce the above
15
#      copyright notice, this list of conditions and the following
16
#      disclaimer in the documentation and/or other materials
17
#      provided with the distribution.
18
#
19
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
# POSSIBILITY OF SUCH DAMAGE.
31
#
32
# The views and conclusions contained in the software and
33
# documentation are those of the authors and should not be
34
# interpreted as representing official policies, either expressed
35
# or implied, of GRNET S.A.
36

    
37
from pithos.tools.lib.client import Pithos_Client, Fault
38
from pithos.tools.lib.util import get_user, get_auth, get_url
39

    
40
from xml.dom import minidom
41
from StringIO import StringIO
42
from hashlib import new as newhasher
43
from binascii import hexlify
44
from httplib import HTTPConnection, HTTPSConnection
45
from urlparse import urlparse
46

    
47
import json
48
import unittest
49
import time as _time
50
import types
51
import hashlib
52
import mimetypes
53
import random
54
import datetime
55
import string
56
import re
57

    
58
DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
59
                "%A, %d-%b-%y %H:%M:%S GMT",
60
                "%a, %d %b %Y %H:%M:%S GMT"]
61

    
62
OTHER_ACCOUNTS = {
63
    '0001': 'verigak',
64
    '0002': 'chazapis',
65
    '0003': 'gtsouk',
66
    '0004': 'papagian',
67
    '0005': 'louridas',
68
    '0006': 'chstath',
69
    '0007': 'pkanavos',
70
    '0008': 'mvasilak',
71
    '0009': 'διογένης'}
72

    
73
class BaseTestCase(unittest.TestCase):
74
    #TODO unauthorized request
75
    def setUp(self):
76
        self.client = Pithos_Client(get_url(), get_auth(), get_user())
77
        self._clean_account()
78
        self.invalid_client = Pithos_Client(get_url(), get_auth(), 'invalid')
79

    
80
        #keep track of initial account groups
81
        self.initial_groups = self.client.retrieve_account_groups()
82

    
83
        #keep track of initial account meta
84
        self.initial_meta = self.client.retrieve_account_metadata(restricted=True)
85

    
86
        self.extended = {
87
            'container':(
88
                'name',
89
                'count',
90
                'bytes',
91
                'last_modified',
92
                'x_container_policy'),
93
            'object':(
94
                'name',
95
                'hash',
96
                'bytes',
97
                'content_type',
98
                'content_encoding',
99
                'last_modified',)}
100
        self.return_codes = (400, 401, 403, 404, 503,)
101

    
102
    def tearDown(self):
103
        #delete additionally created meta
104
        l = []
105
        for m in self.client.retrieve_account_metadata(restricted=True):
106
            if m not in self.initial_meta:
107
                l.append(m)
108
        self.client.delete_account_metadata(l)
109

    
110
        #delete additionally created groups
111
        l = []
112
        for g in self.client.retrieve_account_groups():
113
            if g not in self.initial_groups:
114
                l.append(g)
115
        self.client.unset_account_groups(l)
116
        self._clean_account()
117

    
118
    def _clean_account(self):
119
        for c in self.client.list_containers():
120
            while True:
121
                #list objects returns at most 10000 objects
122
                #so repeat until there are no more objects
123
                objects = self.client.list_objects(c)
124
                if not objects:
125
                    break
126
                for o in objects:
127
                    self.client.delete_object(c, o)
128
            self.client.delete_container(c)
129

    
130
    def assert_status(self, status, codes):
131
        l = [elem for elem in self.return_codes]
132
        if type(codes) == types.ListType:
133
            l.extend(codes)
134
        else:
135
            l.append(codes)
136
        self.assertTrue(status in l)
137

    
138
    def assert_extended(self, data, format, type, size=10000):
139
        if format == 'xml':
140
            self._assert_xml(data, type, size)
141
        elif format == 'json':
142
            self._assert_json(data, type, size)
143

    
144
    def _assert_json(self, data, type, size):
145
        convert = lambda s: s.lower()
146
        info = [convert(elem) for elem in self.extended[type]]
147
        self.assertTrue(len(data) <= size)
148
        for item in info:
149
            for i in data:
150
                if 'subdir' in i.keys():
151
                    continue
152
                self.assertTrue(item in i.keys())
153

    
154
    def _assert_xml(self, data, type, size):
155
        convert = lambda s: s.lower()
156
        info = [convert(elem) for elem in self.extended[type]]
157
        try:
158
            info.remove('content_encoding')
159
        except ValueError:
160
            pass
161
        xml = data
162
        entities = xml.getElementsByTagName(type)
163
        self.assertTrue(len(entities) <= size)
164
        for e in entities:
165
            for item in info:
166
                self.assertTrue(e.getElementsByTagName(item))
167

    
168
    def assert_raises_fault(self, status, callableObj, *args, **kwargs):
169
        """
170
        asserts that a Fault with a specific status is raised
171
        when callableObj is called with the specific arguments
172
        """
173
        try:
174
            r = callableObj(*args, **kwargs)
175
            self.fail('Should never reach here')
176
        except Fault, f:
177
            if type(status) == types.ListType:
178
                self.failUnless(f.status in status)
179
            else:
180
                self.failUnless(f.status == status)
181

    
182
    def assert_not_raises_fault(self, status, callableObj, *args, **kwargs):
183
        """
184
        asserts that a Fault with a specific status is not raised
185
        when callableObj is called with the specific arguments
186
        """
187
        try:
188
            r = callableObj(*args, **kwargs)
189
        except Fault, f:
190
            self.failIfEqual(f.status, status)
191

    
192
    def assert_container_exists(self, container):
193
        """
194
        asserts the existence of a container
195
        """
196
        try:
197
            self.client.retrieve_container_metadata(container)
198
        except Fault, f:
199
            self.failIf(f.status == 404)
200

    
201
    def assert_container_not_exists(self, container):
202
        """
203
        asserts there is no such a container
204
        """
205
        self.assert_raises_fault(404, self.client.retrieve_container_metadata,
206
                                 container)
207

    
208
    def assert_object_exists(self, container, object):
209
        """
210
        asserts the existence of an object
211
        """
212
        try:
213
            self.client.retrieve_object_metadata(container, object)
214
        except Fault, f:
215
            self.failIf(f.status == 404)
216

    
217
    def assert_object_not_exists(self, container, object):
218
        """
219
        asserts there is no such an object
220
        """
221
        self.assert_raises_fault(404, self.client.retrieve_object_metadata,
222
                                 container, object)
223

    
224
    def assert_versionlist_structure(self, versionlist):
225
        self.assertTrue(type(versionlist) == types.ListType)
226
        for elem in versionlist:
227
            self.assertTrue(type(elem) == types.ListType)
228
            self.assertEqual(len(elem), 2)
229

    
230
    def upload_random_data(self, container, name, length=1024, type=None,
231
                           enc=None, **meta):
232
        data = get_random_data(length)
233
        return self.upload_data(container, name, data, type, enc, **meta)
234

    
235
    def upload_data(self, container, name, data, type=None, enc=None, etag=None,
236
                    **meta):
237
        obj = {}
238
        obj['name'] = name
239
        try:
240
            obj['data'] = data
241
            obj['hash'] = compute_md5_hash(obj['data'])
242

    
243
            args = {}
244
            args['etag'] = etag if etag else obj['hash']
245

    
246
            try:
247
                guess = mimetypes.guess_type(name)
248
                type = type if type else guess[0]
249
                enc = enc if enc else guess[1]
250
            except:
251
                pass
252
            args['content_type'] = type if type else 'plain/text'
253
            args['content_encoding'] = enc if enc else None
254

    
255
            obj['meta'] = args
256

    
257
            path = '/%s/%s' % (container, name)
258
            self.client.create_object(container, name, f=StringIO(obj['data']),
259
                                      meta=meta, **args)
260

    
261
            return obj
262
        except IOError:
263
            return
264

    
265
class AccountHead(BaseTestCase):
266
    def setUp(self):
267
        BaseTestCase.setUp(self)
268
        self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
269
        for item in self.containers:
270
            self.client.create_container(item)
271

    
272
        meta = {'foo':'bar'}
273
        self.client.update_account_metadata(**meta)
274
        #self.updated_meta = self.initial_meta.update(meta)
275

    
276
    def test_get_account_meta(self):
277
        meta = self.client.retrieve_account_metadata()
278

    
279
        containers = self.client.list_containers()
280
        l = str(len(containers))
281
        self.assertEqual(meta['x-account-container-count'], l)
282
        size = 0
283
        for c in containers:
284
            m = self.client.retrieve_container_metadata(c)
285
            size = size + int(m['x-container-bytes-used'])
286
        self.assertEqual(meta['x-account-bytes-used'], str(size))
287

    
288
    def test_get_account_403(self):
289
        self.assert_raises_fault(403,
290
                                 self.invalid_client.retrieve_account_metadata)
291

    
292
    def test_get_account_meta_until(self):
293
        t = datetime.datetime.utcnow()
294
        past = t - datetime.timedelta(minutes=-15)
295
        past = int(_time.mktime(past.timetuple()))
296

    
297
        meta = {'premium':True}
298
        self.client.update_account_metadata(**meta)
299
        meta = self.client.retrieve_account_metadata(restricted=True,
300
                                                     until=past)
301
        self.assertTrue('premium' not in meta)
302

    
303
        meta = self.client.retrieve_account_metadata(restricted=True)
304
        self.assertTrue('premium' in meta)
305

    
306
    def test_get_account_meta_until_invalid_date(self):
307
        meta = {'premium':True}
308
        self.client.update_account_metadata(**meta)
309
        meta = self.client.retrieve_account_metadata(restricted=True,
310
                                                     until='kshfksfh')
311
        self.assertTrue('premium' in meta)
312

    
313
class AccountGet(BaseTestCase):
314
    def setUp(self):
315
        BaseTestCase.setUp(self)
316
        #create some containers
317
        self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
318
        for item in self.containers:
319
            self.client.create_container(item)
320

    
321
    def test_list(self):
322
        #list containers
323
        containers = self.client.list_containers()
324
        self.assertEquals(self.containers, containers)
325

    
326
    def test_list_403(self):
327
        self.assert_raises_fault(403, self.invalid_client.list_containers)
328

    
329
    def test_list_with_limit(self):
330
        limit = 2
331
        containers = self.client.list_containers(limit=limit)
332
        self.assertEquals(len(containers), limit)
333
        self.assertEquals(self.containers[:2], containers)
334

    
335
    def test_list_with_marker(self):
336
        l = 2
337
        m = 'bananas'
338
        containers = self.client.list_containers(limit=l, marker=m)
339
        i = self.containers.index(m) + 1
340
        self.assertEquals(self.containers[i:(i+l)], containers)
341

    
342
        m = 'oranges'
343
        containers = self.client.list_containers(limit=l, marker=m)
344
        i = self.containers.index(m) + 1
345
        self.assertEquals(self.containers[i:(i+l)], containers)
346

    
347
    def test_list_json_with_marker(self):
348
        l = 2
349
        m = 'bananas'
350
        containers = self.client.list_containers(limit=l, marker=m, format='json')
351
        self.assert_extended(containers, 'json', 'container', l)
352
        self.assertEqual(containers[0]['name'], 'kiwis')
353
        self.assertEqual(containers[1]['name'], 'oranges')
354

    
355
    def test_list_xml_with_marker(self):
356
        l = 2
357
        m = 'oranges'
358
        xml = self.client.list_containers(limit=l, marker=m, format='xml')
359
        self.assert_extended(xml, 'xml', 'container', l)
360
        nodes = xml.getElementsByTagName('name')
361
        self.assertEqual(len(nodes), 1)
362
        self.assertEqual(nodes[0].childNodes[0].data, 'pears')
363

    
364
    def test_if_modified_since(self):
365
        t = datetime.datetime.utcnow()
366
        t2 = t - datetime.timedelta(minutes=10)
367

    
368
        #add a new container
369
        self.client.create_container('dummy')
370

    
371
        for f in DATE_FORMATS:
372
            past = t2.strftime(f)
373
            try:
374
                c = self.client.list_containers(if_modified_since=past)
375
                self.assertEqual(len(c), len(self.containers) + 1)
376
            except Fault, f:
377
                self.failIf(f.status == 304) #fail if not modified
378
        
379

    
380
    def test_if_modified_since_invalid_date(self):
381
        c = self.client.list_containers(if_modified_since='')
382
        self.assertEqual(len(c), len(self.containers))
383

    
384
    def test_if_not_modified_since(self):
385
        now = datetime.datetime.utcnow()
386
        since = now + datetime.timedelta(1)
387

    
388
        for f in DATE_FORMATS:
389
            args = {'if_modified_since':'%s' %since.strftime(f)}
390

    
391
            #assert not modified
392
            self.assert_raises_fault(304, self.client.list_containers, **args)
393

    
394
    def test_if_unmodified_since(self):
395
        now = datetime.datetime.utcnow()
396
        since = now + datetime.timedelta(1)
397

    
398
        for f in DATE_FORMATS:
399
            c = self.client.list_containers(if_unmodified_since=since.strftime(f))
400

    
401
            #assert success
402
            self.assertEqual(self.containers, c)
403

    
404
    def test_if_unmodified_since_precondition_failed(self):
405
        t = datetime.datetime.utcnow()
406
        t2 = t - datetime.timedelta(minutes=10)
407

    
408
        #add a new container
409
        self.client.create_container('dummy')
410

    
411
        for f in DATE_FORMATS:
412
            past = t2.strftime(f)
413

    
414
            args = {'if_unmodified_since':'%s' %past}
415

    
416
            #assert precondition failed
417
            self.assert_raises_fault(412, self.client.list_containers, **args)
418

    
419
class AccountPost(BaseTestCase):
420
    def setUp(self):
421
        BaseTestCase.setUp(self)
422
        self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
423
        for item in self.containers:
424
            self.client.create_container(item)
425

    
426
        meta = {'foo':'bar'}
427
        self.client.update_account_metadata(**meta)
428
        self.updated_meta = self.initial_meta.update(meta)
429

    
430
    def test_update_meta(self):
431
        with AssertMappingInvariant(self.client.retrieve_account_groups):
432
            meta = {'test':'test', 'tost':'tost'}
433
            self.client.update_account_metadata(**meta)
434

    
435
            meta.update(self.initial_meta)
436
            self.assertEqual(meta,
437
                             self.client.retrieve_account_metadata(
438
                                restricted=True))
439

    
440
    def test_invalid_account_update_meta(self):
441
        meta = {'test':'test', 'tost':'tost'}
442
        self.assert_raises_fault(403,
443
                                 self.invalid_client.update_account_metadata,
444
                                 **meta)
445

    
446
    def test_reset_meta(self):
447
        with AssertMappingInvariant(self.client.retrieve_account_groups):
448
            meta = {'test':'test', 'tost':'tost'}
449
            self.client.update_account_metadata(**meta)
450

    
451
            meta = {'test':'test33'}
452
            self.client.reset_account_metadata(**meta)
453

    
454
            self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
455

    
456
    def test_delete_meta(self):
457
        with AssertMappingInvariant(self.client.retrieve_account_groups):
458
            meta = {'test':'test', 'tost':'tost'}
459
            self.client.update_account_metadata(**meta)
460

    
461
            self.client.delete_account_metadata(meta.keys())
462

    
463
            account_meta = self.client.retrieve_account_metadata(restricted=True)
464
            for m in meta:
465
                self.assertTrue(m not in account_meta.keys())
466

    
467
    def test_set_account_groups(self):
468
        with AssertMappingInvariant(self.client.retrieve_account_metadata):
469
            groups = {'pithosdev':'verigak,gtsouk,chazapis'}
470
            self.client.set_account_groups(**groups)
471

    
472
            self.assertEqual(set(groups['pithosdev']),
473
                             set(self.client.retrieve_account_groups()['pithosdev']))
474

    
475
            more_groups = {'clientsdev':'pkanavos,mvasilak'}
476
            self.client.set_account_groups(**more_groups)
477

    
478
            groups.update(more_groups)
479
            self.assertEqual(set(groups['clientsdev']),
480
                             set(self.client.retrieve_account_groups()['clientsdev']))
481

    
482
    def test_reset_account_groups(self):
483
        with AssertMappingInvariant(self.client.retrieve_account_metadata):
484
            groups = {'pithosdev':'verigak,gtsouk,chazapis',
485
                      'clientsdev':'pkanavos,mvasilak'}
486
            self.client.set_account_groups(**groups)
487

    
488
            self.assertEqual(set(groups['pithosdev'].split(',')),
489
                             set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
490
            self.assertEqual(set(groups['clientsdev'].split(',')),
491
                             set(self.client.retrieve_account_groups()['clientsdev'].split(',')))
492

    
493
            groups = {'pithosdev':'verigak,gtsouk,chazapis,papagian'}
494
            self.client.reset_account_groups(**groups)
495

    
496
            self.assertEqual(set(groups['pithosdev'].split(',')),
497
                             set(self.client.retrieve_account_groups()['pithosdev'].split(',')))
498

    
499
    def test_delete_account_groups(self):
500
        with AssertMappingInvariant(self.client.retrieve_account_metadata):
501
            groups = {'pithosdev':'verigak,gtsouk,chazapis',
502
                      'clientsdev':'pkanavos,mvasilak'}
503
            self.client.set_account_groups(**groups)
504

    
505
            self.client.unset_account_groups(groups.keys())
506

    
507
            self.assertEqual({}, self.client.retrieve_account_groups())
508

    
509
class ContainerHead(BaseTestCase):
510
    def setUp(self):
511
        BaseTestCase.setUp(self)
512
        self.container = 'apples'
513
        self.client.create_container(self.container)
514

    
515
    def test_get_meta(self):
516
        meta = {'trash':'true'}
517
        t1 = datetime.datetime.utcnow()
518
        o = self.upload_random_data(self.container, o_names[0], **meta)
519
        if o:
520
            headers = self.client.retrieve_container_metadata(self.container)
521
            self.assertEqual(headers['x-container-object-count'], '1')
522
            self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
523
            t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
524
            delta = (t2 - t1)
525
            threashold = datetime.timedelta(seconds=1)
526
            self.assertTrue(delta < threashold)
527
            self.assertTrue(headers['x-container-object-meta'])
528
            self.assertTrue('Trash' in headers['x-container-object-meta'])
529

    
530
class ContainerGet(BaseTestCase):
531
    def setUp(self):
532
        BaseTestCase.setUp(self)
533
        self.container = ['pears', 'apples']
534
        for c in self.container:
535
            self.client.create_container(c)
536
        self.obj = []
537
        for o in o_names[:8]:
538
            self.obj.append(self.upload_random_data(self.container[0], o))
539
        for o in o_names[8:]:
540
            self.obj.append(self.upload_random_data(self.container[1], o))
541

    
542
    def test_list_objects(self):
543
        objects = self.client.list_objects(self.container[0])
544
        l = [elem['name'] for elem in self.obj[:8]]
545
        l.sort()
546
        self.assertEqual(objects, l)
547

    
548
    def test_list_objects_containing_slash(self):
549
        self.client.create_container('test')
550
        self.upload_random_data('test', '/objectname')
551

    
552
        objects = self.client.list_objects('test')
553
        self.assertEqual(objects, ['/objectname'])
554

    
555
        objects = self.client.list_objects('test', format='json')
556
        self.assertEqual(objects[0]['name'], '/objectname')
557

    
558
        objects = self.client.list_objects('test', format='xml')
559
        self.assert_extended(objects, 'xml', 'object')
560
        node_name = objects.getElementsByTagName('name')[0]
561
        self.assertEqual(node_name.firstChild.data, '/objectname')
562

    
563
    def test_list_objects_with_limit_marker(self):
564
        objects = self.client.list_objects(self.container[0], limit=2)
565
        l = [elem['name'] for elem in self.obj[:8]]
566
        l.sort()
567
        self.assertEqual(objects, l[:2])
568

    
569
        markers = ['How To Win Friends And Influence People.pdf',
570
                   'moms_birthday.jpg']
571
        limit = 4
572
        for m in markers:
573
            objects = self.client.list_objects(self.container[0], limit=limit,
574
                                               marker=m)
575
            l = [elem['name'] for elem in self.obj[:8]]
576
            l.sort()
577
            start = l.index(m) + 1
578
            end = start + limit
579
            end = end if len(l) >= end else len(l)
580
            self.assertEqual(objects, l[start:end])
581

    
582
    #takes too long
583
    def _test_list_limit_exceeds(self):
584
        self.client.create_container('pithos')
585

    
586
        for i in range(10001):
587
            self.client.create_zero_length_object('pithos', i)
588

    
589
        self.assertEqual(10000, len(self.client.list_objects('pithos')))
590

    
591
    def test_list_empty_params(self):
592
        objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
593
        if objects:
594
            objects = objects.strip().split('\n')
595
        self.assertEqual(objects,
596
                         self.client.list_objects(self.container[0]))
597

    
598
    def test_list_pseudo_hierarchical_folders(self):
599
        objects = self.client.list_objects(self.container[1], prefix='photos',
600
                                           delimiter='/')
601
        self.assertEquals(['photos/animals/', 'photos/me.jpg',
602
                           'photos/plants/'], objects)
603

    
604
        objects = self.client.list_objects(self.container[1],
605
                                           prefix='photos/animals',
606
                                           delimiter='/')
607
        l = ['photos/animals/cats/', 'photos/animals/dogs/']
608
        self.assertEquals(l, objects)
609

    
610
        objects = self.client.list_objects(self.container[1], path='photos')
611
        self.assertEquals(['photos/me.jpg'], objects)
612

    
613
    def test_extended_list_json(self):
614
        objects = self.client.list_objects(self.container[1], format='json',
615
                                           limit=2, prefix='photos/animals',
616
                                           delimiter='/')
617
        self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
618
        self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
619

    
620
    def test_extended_list_xml(self):
621
        xml = self.client.list_objects(self.container[1], format='xml', limit=4,
622
                                       prefix='photos', delimiter='/')
623
        self.assert_extended(xml, 'xml', 'object', size=4)
624
        dirs = xml.getElementsByTagName('subdir')
625
        self.assertEqual(len(dirs), 2)
626
        self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
627
        self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
628

    
629
        objects = xml.getElementsByTagName('name')
630
        self.assertEqual(len(objects), 1)
631
        self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
632

    
633
    def test_list_meta_double_matching(self):
634
        meta = {'quality':'aaa', 'stock':'true'}
635
        self.client.update_object_metadata(self.container[0],
636
                                           self.obj[0]['name'], **meta)
637
        obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
638
        self.assertEqual(len(obj), 1)
639
        self.assertTrue(obj, self.obj[0]['name'])
640

    
641
    def test_list_using_meta(self):
642
        meta = {'quality':'aaa'}
643
        for o in self.obj[:2]:
644
            self.client.update_object_metadata(self.container[0], o['name'],
645
                                               **meta)
646
        meta = {'stock':'true'}
647
        for o in self.obj[3:5]:
648
            self.client.update_object_metadata(self.container[0], o['name'],
649
                                               **meta)
650

    
651
        obj = self.client.list_objects(self.container[0], meta='Quality')
652
        self.assertEqual(len(obj), 2)
653
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
654

    
655
        # test case insensitive
656
        obj = self.client.list_objects(self.container[0], meta='quality')
657
        self.assertEqual(len(obj), 2)
658
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
659

    
660
        # test multiple matches
661
        obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
662
        self.assertEqual(len(obj), 4)
663
        self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
664

    
665
        # test non 1-1 multiple match
666
        obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
667
        self.assertEqual(len(obj), 2)
668
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
669

    
670
    def test_if_modified_since(self):
671
        t = datetime.datetime.utcnow()
672
        t2 = t - datetime.timedelta(minutes=10)
673

    
674
        #add a new object
675
        self.upload_random_data(self.container[0], o_names[0])
676

    
677
        for f in DATE_FORMATS:
678
            past = t2.strftime(f)
679
            try:
680
                o = self.client.list_objects(self.container[0],
681
                                            if_modified_since=past)
682
                self.assertEqual(o,
683
                                 self.client.list_objects(self.container[0]))
684
            except Fault, f:
685
                self.failIf(f.status == 304) #fail if not modified
686

    
687
    def test_if_modified_since_invalid_date(self):
688
        headers = {'if-modified-since':''}
689
        o = self.client.list_objects(self.container[0], if_modified_since='')
690
        self.assertEqual(o, self.client.list_objects(self.container[0]))
691

    
692
    def test_if_not_modified_since(self):
693
        now = datetime.datetime.utcnow()
694
        since = now + datetime.timedelta(1)
695

    
696
        for f in DATE_FORMATS:
697
            args = {'if_modified_since':'%s' %since.strftime(f)}
698

    
699
            #assert not modified
700
            self.assert_raises_fault(304, self.client.list_objects,
701
                                     self.container[0], **args)
702

    
703
    def test_if_unmodified_since(self):
704
        now = datetime.datetime.utcnow()
705
        since = now + datetime.timedelta(1)
706

    
707
        for f in DATE_FORMATS:
708
            obj = self.client.list_objects(self.container[0],
709
                                           if_unmodified_since=since.strftime(f))
710

    
711
            #assert unmodified
712
            self.assertEqual(obj, self.client.list_objects(self.container[0]))
713

    
714
    def test_if_unmodified_since_precondition_failed(self):
715
        t = datetime.datetime.utcnow()
716
        t2 = t - datetime.timedelta(minutes=10)
717

    
718
        #add a new container
719
        self.client.create_container('dummy')
720

    
721
        for f in DATE_FORMATS:
722
            past = t2.strftime(f)
723

    
724
            args = {'if_unmodified_since':'%s' %past}
725

    
726
            #assert precondition failed
727
            self.assert_raises_fault(412, self.client.list_objects,
728
                                     self.container[0], **args)
729

    
730
class ContainerPut(BaseTestCase):
731
    def setUp(self):
732
        BaseTestCase.setUp(self)
733
        self.containers = ['c1', 'c2']
734

    
735
    def test_create(self):
736
        self.client.create_container(self.containers[0])
737
        containers = self.client.list_containers()
738
        self.assertTrue(self.containers[0] in containers)
739
        self.assert_container_exists(self.containers[0])
740

    
741
    def test_create_twice(self):
742
        self.client.create_container(self.containers[0])
743
        self.assertTrue(not self.client.create_container(self.containers[0]))
744

    
745
    def test_quota(self):
746
        self.client.create_container(self.containers[0])
747

    
748
        policy = {'quota':100}
749
        self.client.set_container_policies('c1', **policy)
750

    
751
        meta = self.client.retrieve_container_metadata('c1')
752
        self.assertTrue('x-container-policy-quota' in meta)
753
        self.assertEqual(meta['x-container-policy-quota'], '100')
754

    
755
        args = ['c1', 'o1']
756
        kwargs = {'length':101}
757
        self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
758

    
759
        #reset quota
760
        policy = {'quota':0}
761
        self.client.set_container_policies('c1', **policy)
762

    
763
class ContainerPost(BaseTestCase):
764
    def setUp(self):
765
        BaseTestCase.setUp(self)
766
        self.container = 'apples'
767
        self.client.create_container(self.container)
768

    
769
    def test_update_meta(self):
770
        meta = {'test':'test33',
771
                'tost':'tost22'}
772
        self.client.update_container_metadata(self.container, **meta)
773
        headers = self.client.retrieve_container_metadata(self.container)
774
        for k,v in meta.items():
775
            k = 'x-container-meta-%s' % k
776
            self.assertTrue(headers[k])
777
            self.assertEqual(headers[k], v)
778

    
779
class ContainerDelete(BaseTestCase):
780
    def setUp(self):
781
        BaseTestCase.setUp(self)
782
        self.containers = ['c1', 'c2']
783
        for c in self.containers:
784
            self.client.create_container(c)
785

    
786
    def test_delete(self):
787
        status = self.client.delete_container(self.containers[0])[0]
788
        self.assertEqual(status, 204)
789

    
790
    def test_delete_non_empty(self):
791
        self.upload_random_data(self.containers[1], o_names[0])
792
        self.assert_raises_fault(409, self.client.delete_container,
793
                                 self.containers[1])
794

    
795
    def test_delete_invalid(self):
796
        self.assert_raises_fault(404, self.client.delete_container, 'c3')
797

    
798
class ObjectGet(BaseTestCase):
799
    def setUp(self):
800
        BaseTestCase.setUp(self)
801
        self.containers = ['c1', 'c2']
802
        #create some containers
803
        for c in self.containers:
804
            self.client.create_container(c)
805

    
806
        #upload a file
807
        names = ('obj1', 'obj2')
808
        self.objects = []
809
        for n in names:
810
            self.objects.append(self.upload_random_data(self.containers[1], n))
811

    
812
    def test_versions(self):
813
        c = self.containers[1]
814
        o = self.objects[0]
815
        b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
816
        self.assert_versionlist_structure(b)
817

    
818
        #update meta
819
        meta = {'quality':'AAA', 'stock':True}
820
        self.client.update_object_metadata(c, o['name'], **meta)
821

    
822
        a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
823
        self.assert_versionlist_structure(a)
824
        self.assertEqual(len(b)+1, len(a))
825
        self.assertEqual(b, a[:-1])
826

    
827
        #get exact previous version metadata
828
        v = a[-2][0]
829
        v_meta = self.client.retrieve_object_metadata(c, o['name'],
830
                                                      restricted=True,
831
                                                      version=v)
832
        for k in meta.keys():
833
            self.assertTrue(k not in v_meta)
834

    
835
        #update obejct
836
        data = get_random_data()
837
        self.client.update_object(c, o['name'], StringIO(data))
838

    
839
        aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
840
        self.assert_versionlist_structure(aa)
841
        self.assertEqual(len(a)+1, len(aa))
842
        self.assertEqual(a, aa[:-1])
843

    
844
        #get exact previous version
845
        v = aa[-3][0]
846
        v_data = self.client.retrieve_object_version(c, o['name'], version=v)
847
        self.assertEqual(o['data'], v_data)
848
        self.assertEqual(self.client.retrieve_object(c, o['name']),
849
                         '%s%s' %(v_data, data))
850

    
851
    def test_get(self):
852
        #perform get
853
        o = self.client.retrieve_object(self.containers[1],
854
                                        self.objects[0]['name'],
855
                                        self.objects[0]['meta'])
856
        self.assertEqual(o, self.objects[0]['data'])
857

    
858
    def test_objects_with_trailing_spaces(self):
859
        self.client.create_container('test')
860
        #create 'a' object
861
        self.upload_random_data('test', 'a')
862
        #look for 'a ' object
863
        self.assert_raises_fault(404, self.client.retrieve_object,
864
                                 'test', 'a ')
865

    
866
        #delete 'a' object
867
        self.client.delete_object('test', 'a')
868
        self.assert_raises_fault(404, self.client.retrieve_object,
869
                                 'test', 'a')
870

    
871
        #create 'a ' object
872
        self.upload_random_data('test', 'a ')
873
        #look for 'a' object
874
        self.assert_raises_fault(404, self.client.retrieve_object,
875
                                 'test', 'a')
876

    
877
    def test_get_invalid(self):
878
        self.assert_raises_fault(404, self.client.retrieve_object,
879
                                 self.containers[0], self.objects[0]['name'])
880

    
881
    def test_get_partial(self):
882
        #perform get with range
883
        status, headers, data = self.client.request_object(self.containers[1],
884
                                                            self.objects[0]['name'],
885
                                                            range='bytes=0-499')
886

    
887
        #assert successful partial content
888
        self.assertEqual(status, 206)
889

    
890
        #assert content-type
891
        self.assertEqual(headers['content-type'],
892
                         self.objects[0]['meta']['content_type'])
893

    
894
        #assert content length
895
        self.assertEqual(int(headers['content-length']), 500)
896

    
897
        #assert content
898
        self.assertEqual(self.objects[0]['data'][:500], data)
899

    
900
    def test_get_final_500(self):
901
        #perform get with range
902
        headers = {'range':'bytes=-500'}
903
        status, headers, data = self.client.request_object(self.containers[1],
904
                                                            self.objects[0]['name'],
905
                                                            range='bytes=-500')
906

    
907
        #assert successful partial content
908
        self.assertEqual(status, 206)
909

    
910
        #assert content-type
911
        self.assertEqual(headers['content-type'],
912
                         self.objects[0]['meta']['content_type'])
913

    
914
        #assert content length
915
        self.assertEqual(int(headers['content-length']), 500)
916

    
917
        #assert content
918
        self.assertTrue(self.objects[0]['data'][-500:], data)
919

    
920
    def test_get_rest(self):
921
        #perform get with range
922
        offset = len(self.objects[0]['data']) - 500
923
        status, headers, data = self.client.request_object(self.containers[1],
924
                                                self.objects[0]['name'],
925
                                                range='bytes=%s-' %offset)
926

    
927
        #assert successful partial content
928
        self.assertEqual(status, 206)
929

    
930
        #assert content-type
931
        self.assertEqual(headers['content-type'],
932
                         self.objects[0]['meta']['content_type'])
933

    
934
        #assert content length
935
        self.assertEqual(int(headers['content-length']), 500)
936

    
937
        #assert content
938
        self.assertTrue(self.objects[0]['data'][-500:], data)
939

    
940
    def test_get_range_not_satisfiable(self):
941
        #perform get with range
942
        offset = len(self.objects[0]['data']) + 1
943

    
944
        #assert range not satisfiable
945
        self.assert_raises_fault(416, self.client.retrieve_object,
946
                                 self.containers[1], self.objects[0]['name'],
947
                                 range='bytes=0-%s' %offset)
948

    
949
    def test_multiple_range(self):
950
        #perform get with multiple range
951
        ranges = ['0-499', '-500', '1000-']
952
        bytes = 'bytes=%s' % ','.join(ranges)
953
        status, headers, data = self.client.request_object(self.containers[1],
954
                                                           self.objects[0]['name'],
955
                                                           range=bytes)
956

    
957
        # assert partial content
958
        self.assertEqual(status, 206)
959

    
960
        # assert Content-Type of the reply will be multipart/byteranges
961
        self.assertTrue(headers['content-type'])
962
        content_type_parts = headers['content-type'].split()
963
        self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
964

    
965
        boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
966
        cparts = data.split(boundary)[1:-1]
967

    
968
        # assert content parts are exactly 2
969
        self.assertEqual(len(cparts), len(ranges))
970

    
971
        # for each content part assert headers
972
        i = 0
973
        for cpart in cparts:
974
            content = cpart.split('\r\n')
975
            headers = content[1:3]
976
            content_range = headers[0].split(': ')
977
            self.assertEqual(content_range[0], 'Content-Range')
978

    
979
            r = ranges[i].split('-')
980
            if not r[0] and not r[1]:
981
                pass
982
            elif not r[0]:
983
                start = len(self.objects[0]['data']) - int(r[1])
984
                end = len(self.objects[0]['data'])
985
            elif not r[1]:
986
                start = int(r[0])
987
                end = len(self.objects[0]['data'])
988
            else:
989
                start = int(r[0])
990
                end = int(r[1]) + 1
991
            fdata = self.objects[0]['data'][start:end]
992
            sdata = '\r\n'.join(content[4:-1])
993
            self.assertEqual(len(fdata), len(sdata))
994
            self.assertEquals(fdata, sdata)
995
            i+=1
996

    
997
    def test_multiple_range_not_satisfiable(self):
998
        #perform get with multiple range
999
        out_of_range = len(self.objects[0]['data']) + 1
1000
        ranges = ['0-499', '-500', '%d-' %out_of_range]
1001
        bytes = 'bytes=%s' % ','.join(ranges)
1002

    
1003
        # assert partial content
1004
        self.assert_raises_fault(416, self.client.retrieve_object,
1005
                                 self.containers[1],
1006
                                 self.objects[0]['name'], range=bytes)
1007

    
1008
    def test_get_with_if_match(self):
1009
        #perform get with If-Match
1010
        etag = self.objects[0]['hash']
1011
        status, headers, data = self.client.request_object(self.containers[1],
1012
                                                           self.objects[0]['name'],
1013
                                                           if_match=etag)
1014
        #assert get success
1015
        self.assertEqual(status, 200)
1016

    
1017
        #assert content-type
1018
        self.assertEqual(headers['content-type'],
1019
                         self.objects[0]['meta']['content_type'])
1020

    
1021
        #assert response content
1022
        self.assertEqual(self.objects[0]['data'], data)
1023

    
1024
    def test_get_with_if_match_star(self):
1025
        #perform get with If-Match *
1026
        headers = {'if-match':'*'}
1027
        status, headers, data = self.client.request_object(self.containers[1],
1028
                                                self.objects[0]['name'],
1029
                                                **headers)
1030
        #assert get success
1031
        self.assertEqual(status, 200)
1032

    
1033
        #assert content-type
1034
        self.assertEqual(headers['content-type'],
1035
                         self.objects[0]['meta']['content_type'])
1036

    
1037
        #assert response content
1038
        self.assertEqual(self.objects[0]['data'], data)
1039

    
1040
    def test_get_with_multiple_if_match(self):
1041
        #perform get with If-Match
1042
        etags = [i['hash'] for i in self.objects if i]
1043
        etags = ','.join('"%s"' % etag for etag in etags)
1044
        status, headers, data = self.client.request_object(self.containers[1],
1045
                                                           self.objects[0]['name'],
1046
                                                           if_match=etags)
1047
        #assert get success
1048
        self.assertEqual(status, 200)
1049

    
1050
        #assert content-type
1051
        self.assertEqual(headers['content-type'],
1052
                         self.objects[0]['meta']['content_type'])
1053

    
1054
        #assert content-type
1055
        self.assertEqual(headers['content-type'],
1056
                         self.objects[0]['meta']['content_type'])
1057

    
1058
        #assert response content
1059
        self.assertEqual(self.objects[0]['data'], data)
1060

    
1061
    def test_if_match_precondition_failed(self):
1062
        #assert precondition failed
1063
        self.assert_raises_fault(412, self.client.retrieve_object,
1064
                                 self.containers[1],
1065
                                 self.objects[0]['name'], if_match='123')
1066

    
1067
    def test_if_none_match(self):
1068
        #perform get with If-None-Match
1069
        status, headers, data = self.client.request_object(self.containers[1],
1070
                                                           self.objects[0]['name'],
1071
                                                           if_none_match='123')
1072

    
1073
        #assert get success
1074
        self.assertEqual(status, 200)
1075

    
1076
        #assert content-type
1077
        self.assertEqual(headers['content_type'],
1078
                         self.objects[0]['meta']['content_type'])
1079

    
1080
    def test_if_none_match(self):
1081
        #perform get with If-None-Match * and assert not modified
1082
        self.assert_raises_fault(304, self.client.retrieve_object,
1083
                                 self.containers[1],
1084
                                 self.objects[0]['name'],
1085
                                 if_none_match='*')
1086

    
1087
    def test_if_none_match_not_modified(self):
1088
        #perform get with If-None-Match and assert not modified
1089
        self.assert_raises_fault(304, self.client.retrieve_object,
1090
                                 self.containers[1],
1091
                                 self.objects[0]['name'],
1092
                                 if_none_match=self.objects[0]['hash'])
1093

    
1094
        meta = self.client.retrieve_object_metadata(self.containers[1],
1095
                                                    self.objects[0]['name'])
1096
        self.assertEqual(meta['etag'], self.objects[0]['hash'])
1097

    
1098
    def test_if_modified_since(self):
1099
        t = datetime.datetime.utcnow()
1100
        t2 = t - datetime.timedelta(minutes=10)
1101

    
1102
        #modify the object
1103
        self.upload_data(self.containers[1],
1104
                           self.objects[0]['name'],
1105
                           self.objects[0]['data'][:200])
1106

    
1107
        for f in DATE_FORMATS:
1108
            past = t2.strftime(f)
1109

    
1110
            headers = {'if-modified-since':'%s' %past}
1111
            try:
1112
                o = self.client.retrieve_object(self.containers[1],
1113
                                                self.objects[0]['name'],
1114
                                                if_modified_since=past)
1115
                self.assertEqual(o,
1116
                                 self.client.retrieve_object(self.containers[1],
1117
                                                             self.objects[0]['name']))
1118
            except Fault, f:
1119
                self.failIf(f.status == 304)
1120

    
1121
    def test_if_modified_since_invalid_date(self):
1122
        o = self.client.retrieve_object(self.containers[1],
1123
                                        self.objects[0]['name'],
1124
                                        if_modified_since='')
1125
        self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1126
                                                        self.objects[0]['name']))
1127

    
1128
    def test_if_not_modified_since(self):
1129
        now = datetime.datetime.utcnow()
1130
        since = now + datetime.timedelta(1)
1131

    
1132
        for f in DATE_FORMATS:
1133
            #assert not modified
1134
            self.assert_raises_fault(304, self.client.retrieve_object,
1135
                                     self.containers[1], self.objects[0]['name'],
1136
                                     if_modified_since=since.strftime(f))
1137

    
1138
    def test_if_unmodified_since(self):
1139
        now = datetime.datetime.utcnow()
1140
        since = now + datetime.timedelta(1)
1141

    
1142
        for f in DATE_FORMATS:
1143
            t = since.strftime(f)
1144
            status, headers, data = self.client.request_object(self.containers[1],
1145
                                                               self.objects[0]['name'],
1146
                                                               if_unmodified_since=t)
1147
            #assert success
1148
            self.assertEqual(status, 200)
1149
            self.assertEqual(self.objects[0]['data'], data)
1150

    
1151
            #assert content-type
1152
            self.assertEqual(headers['content-type'],
1153
                             self.objects[0]['meta']['content_type'])
1154

    
1155
    def test_if_unmodified_since_precondition_failed(self):
1156
        t = datetime.datetime.utcnow()
1157
        t2 = t - datetime.timedelta(minutes=10)
1158

    
1159
        #modify the object
1160
        self.upload_data(self.containers[1],
1161
                           self.objects[0]['name'],
1162
                           self.objects[0]['data'][:200])
1163

    
1164
        for f in DATE_FORMATS:
1165
            past = t2.strftime(f)
1166
            #assert precondition failed
1167
            self.assert_raises_fault(412, self.client.retrieve_object,
1168
                                     self.containers[1], self.objects[0]['name'],
1169
                                     if_unmodified_since=past)
1170

    
1171
    def test_hashes(self):
1172
        l = 8388609
1173
        fname = 'largefile'
1174
        o = self.upload_random_data(self.containers[1], fname, l)
1175
        if o:
1176
            body = self.client.retrieve_object(self.containers[1], fname,
1177
                                               format='json')
1178
            hashes = body['hashes']
1179
            block_size = body['block_size']
1180
            block_hash = body['block_hash']
1181
            block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1182
            self.assertTrue(len(hashes), block_num)
1183
            i = 0
1184
            for h in hashes:
1185
                start = i * block_size
1186
                end = (i + 1) * block_size
1187
                hash = compute_block_hash(o['data'][start:end], block_hash)
1188
                self.assertEqual(h, hash)
1189
                i += 1
1190

    
1191
class ObjectPut(BaseTestCase):
1192
    def setUp(self):
1193
        BaseTestCase.setUp(self)
1194
        self.container = 'c1'
1195
        self.client.create_container(self.container)
1196

    
1197
    def test_upload(self):
1198
        name = o_names[0]
1199
        meta = {'test':'test1'}
1200
        o = self.upload_random_data(self.container, name, **meta)
1201

    
1202
        headers = self.client.retrieve_object_metadata(self.container,
1203
                                                       name,
1204
                                                       restricted=True)
1205
        self.assertTrue('test' in headers.keys())
1206
        self.assertEqual(headers['test'], meta['test'])
1207

    
1208
        #assert uploaded content
1209
        status, h, data = self.client.request_object(self.container, name)
1210
        self.assertEqual(len(o['data']), int(h['content-length']))
1211
        self.assertEqual(o['data'], data)
1212

    
1213
        #assert content-type
1214
        self.assertEqual(h['content-type'], o['meta']['content_type'])
1215

    
1216
    def _test_maximum_upload_size_exceeds(self):
1217
        name = o_names[0]
1218
        meta = {'test':'test1'}
1219
        #upload 100MB
1220
        length=1024*1024*100
1221
        self.assert_raises_fault(400, self.upload_random_data, self.container,
1222
                                 name, length, **meta)
1223

    
1224
    def test_upload_with_name_containing_slash(self):
1225
        name = '/%s' % o_names[0]
1226
        meta = {'test':'test1'}
1227
        o = self.upload_random_data(self.container, name, **meta)
1228

    
1229
        self.assertEqual(o['data'],
1230
                         self.client.retrieve_object(self.container, name))
1231

    
1232
        self.assertTrue(name in self.client.list_objects(self.container))
1233

    
1234
    def test_create_directory_marker(self):
1235
        self.client.create_directory_marker(self.container, 'foo')
1236
        meta = self.client.retrieve_object_metadata(self.container, 'foo')
1237
        self.assertEqual(meta['content-length'], '0')
1238
        self.assertEqual(meta['content-type'], 'application/directory')
1239

    
1240
    def test_upload_unprocessable_entity(self):
1241
        meta={'etag':'123', 'test':'test1'}
1242

    
1243
        #assert unprocessable entity
1244
        self.assert_raises_fault(422, self.upload_random_data, self.container,
1245
                                 o_names[0], **meta)
1246

    
1247
    def test_chunked_transfer(self):
1248
        data = get_random_data()
1249
        objname = 'object'
1250
        self.client.create_object_using_chunks(self.container, objname,
1251
                                               StringIO(data))
1252

    
1253
        uploaded_data = self.client.retrieve_object(self.container, objname)
1254
        self.assertEqual(data, uploaded_data)
1255

    
1256
    def test_manifestation(self):
1257
        prefix = 'myobject/'
1258
        data = ''
1259
        for i in range(5):
1260
            part = '%s%d' %(prefix, i)
1261
            o = self.upload_random_data(self.container, part)
1262
            data += o['data']
1263

    
1264
        manifest = '%s/%s' %(self.container, prefix)
1265
        self.client.create_manifestation(self.container, 'large-object', manifest)
1266

    
1267
        self.assert_object_exists(self.container, 'large-object')
1268
        self.assertEqual(data, self.client.retrieve_object(self.container,
1269
                                                           'large-object'))
1270
        
1271
        r = self.client.retrieve_object_hashmap(self.container,'large-object')
1272
        hashes = r['hashes']
1273
        block_size = int(r['block_size'])
1274
        block_hash = r['block_hash']
1275
        l = len(data)
1276
        block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1277
        self.assertEqual(block_num, len(hashes))
1278
        
1279
        #wrong manifestation
1280
        self.client.create_manifestation(self.container, 'large-object',
1281
                                         '%s/invalid' % self.container)
1282
        self.assertEqual('', self.client.retrieve_object(self.container,
1283
                                                         'large-object'))
1284

    
1285
    def test_create_zero_length_object(self):
1286
        c = self.container
1287
        o = 'object'
1288
        zero = self.client.create_zero_length_object(c, o)
1289
        zero_meta = self.client.retrieve_object_metadata(c, o)
1290
        zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1291
        zero_data = self.client.retrieve_object(c, o)
1292

    
1293
        self.assertEqual(int(zero_meta['content-length']), 0)
1294
        hasher = newhasher('sha256')
1295
        hasher.update("")
1296
        emptyhash = hasher.digest()
1297
        self.assertEqual(zero_hash, [hexlify(emptyhash)])
1298
        self.assertEqual(zero_data, '')
1299

    
1300
    def test_create_object_by_hashmap(self):
1301
        c = self.container
1302
        o = 'object'
1303
        self.upload_random_data(c, o)
1304
        hashmap = self.client.retrieve_object(c, o, format='json')
1305
        o2 = 'object-copy'
1306
        self.client.create_object_by_hashmap(c, o2, hashmap)
1307
        self.assertEqual(self.client.retrieve_object(c, o),
1308
                         self.client.retrieve_object(c, o))
1309

    
1310
class ObjectCopy(BaseTestCase):
1311
    def setUp(self):
1312
        BaseTestCase.setUp(self)
1313
        self.containers = ['c1', 'c2']
1314
        for c in self.containers:
1315
            self.client.create_container(c)
1316
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1317

    
1318
    def test_copy(self):
1319
        with AssertMappingInvariant(self.client.retrieve_object_metadata,
1320
                             self.containers[0], self.obj['name']):
1321
            #perform copy
1322
            meta = {'test':'testcopy'}
1323
            status = self.client.copy_object(self.containers[0],
1324
                                              self.obj['name'],
1325
                                              self.containers[0],
1326
                                              'testcopy',
1327
                                              meta)[0]
1328

    
1329
            #assert copy success
1330
            self.assertEqual(status, 201)
1331

    
1332
            #assert access the new object
1333
            headers = self.client.retrieve_object_metadata(self.containers[0],
1334
                                                           'testcopy')
1335
            self.assertTrue('x-object-meta-test' in headers.keys())
1336
            self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1337

    
1338
            #assert etag is the same
1339
            self.assertEqual(headers['etag'], self.obj['hash'])
1340

    
1341
            #assert src object still exists
1342
            self.assert_object_exists(self.containers[0], self.obj['name'])
1343

    
1344
    def test_copy_from_different_container(self):
1345
        with AssertMappingInvariant(self.client.retrieve_object_metadata,
1346
                             self.containers[0], self.obj['name']):
1347
            meta = {'test':'testcopy'}
1348
            status = self.client.copy_object(self.containers[0],
1349
                                             self.obj['name'],
1350
                                             self.containers[1],
1351
                                             'testcopy',
1352
                                             meta)[0]
1353
            self.assertEqual(status, 201)
1354

    
1355
            # assert updated metadata
1356
            meta = self.client.retrieve_object_metadata(self.containers[1],
1357
                                                           'testcopy',
1358
                                                           restricted=True)
1359
            self.assertTrue('test' in meta.keys())
1360
            self.assertTrue(meta['test'], 'testcopy')
1361

    
1362
            #assert src object still exists
1363
            self.assert_object_exists(self.containers[0], self.obj['name'])
1364

    
1365
    def test_copy_invalid(self):
1366
        #copy from invalid object
1367
        meta = {'test':'testcopy'}
1368
        self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1369
                                 'test.py', self.containers[1], 'testcopy', meta)
1370

    
1371
        #copy from invalid container
1372
        meta = {'test':'testcopy'}
1373
        self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1374
                                 self.obj['name'], self.containers[1],
1375
                                 'testcopy', meta)
1376

    
1377
class ObjectMove(BaseTestCase):
1378
    def setUp(self):
1379
        BaseTestCase.setUp(self)
1380
        self.containers = ['c1', 'c2']
1381
        for c in self.containers:
1382
            self.client.create_container(c)
1383
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1384

    
1385
    def test_move(self):
1386
        meta = self.client.retrieve_object_metadata(self.containers[0],
1387
                                                    self.obj['name'])
1388
        self.assertTrue('x-object-uuid' in meta)
1389
        uuid = meta['x-object-uuid']
1390

    
1391
        #perform move
1392
        meta = {'test':'testcopy'}
1393
        src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1394
        status = self.client.move_object(self.containers[0], self.obj['name'],
1395
                                         self.containers[0], 'testcopy',
1396
                                         meta)[0]
1397

    
1398
        #assert successful move
1399
        self.assertEqual(status, 201)
1400

    
1401
        #assert updated metadata
1402
        meta = self.client.retrieve_object_metadata(self.containers[0],
1403
                                                    'testcopy')
1404
        self.assertTrue('x-object-meta-test' in meta.keys())
1405
        self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1406

    
1407
        #assert same uuid
1408
        self.assertTrue(meta['x-object-uuid'], uuid)
1409

    
1410
        #assert src object no more exists
1411
        self.assert_object_not_exists(self.containers[0], self.obj['name'])
1412

    
1413
class ObjectPost(BaseTestCase):
1414
    def setUp(self):
1415
        BaseTestCase.setUp(self)
1416
        self.containers = ['c1', 'c2']
1417
        for c in self.containers:
1418
            self.client.create_container(c)
1419
        self.obj = []
1420
        for i in range(2):
1421
            self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1422

    
1423
    def test_update_meta(self):
1424
        with AssertUUidInvariant(self.client.retrieve_object_metadata,
1425
                                 self.containers[0],
1426
                                 self.obj[0]['name']):
1427
            #perform update metadata
1428
            more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1429
            status = self.client.update_object_metadata(self.containers[0],
1430
                                                        self.obj[0]['name'],
1431
                                                        **more)[0]
1432
            #assert request accepted
1433
            self.assertEqual(status, 202)
1434

    
1435
            #assert old metadata are still there
1436
            headers = self.client.retrieve_object_metadata(self.containers[0],
1437
                                                           self.obj[0]['name'],
1438
                                                           restricted=True)
1439
            #assert new metadata have been updated
1440
            for k,v in more.items():
1441
                self.assertTrue(k in headers.keys())
1442
                self.assertTrue(headers[k], v)
1443

    
1444
            #out of limits
1445
            more = {'f' * 114: 'b' * 257}
1446
            self.assert_raises_fault(400, self.client.update_object_metadata,
1447
                                                        self.containers[0],
1448
                                                        self.obj[0]['name'],
1449
                                                        **more)
1450
            
1451
            #perform update metadata
1452
            more = {'α': 'β' * 256}
1453
            status = self.client.update_object_metadata(self.containers[0],
1454
                                                        self.obj[0]['name'],
1455
                                                        **more)[0]
1456
            #assert request accepted
1457
            self.assertEqual(status, 202)
1458
            
1459
            #assert old metadata are still there
1460
            headers = self.client.retrieve_object_metadata(self.containers[0],
1461
                                                           self.obj[0]['name'],
1462
                                                           restricted=True)
1463
            #assert new metadata have been updated
1464
            for k,v in more.items():
1465
                self.assertTrue(k in headers.keys())
1466
                self.assertTrue(headers[k], v)
1467
            
1468
            #out of limits
1469
            more = {'α': 'β' * 257}
1470
            self.assert_raises_fault(400, self.client.update_object_metadata,
1471
                                                        self.containers[0],
1472
                                                        self.obj[0]['name'],
1473
                                                        **more)
1474
    
1475
    def test_update_object(self,
1476
                           first_byte_pos=0,
1477
                           last_byte_pos=499,
1478
                           instance_length = True,
1479
                           content_length = 500):
1480
        with AssertUUidInvariant(self.client.retrieve_object_metadata,
1481
                                 self.containers[0],
1482
                                 self.obj[0]['name']):
1483
            l = len(self.obj[0]['data'])
1484
            range = 'bytes %d-%d/%s' %(first_byte_pos,
1485
                                           last_byte_pos,
1486
                                            l if instance_length else '*')
1487
            partial = last_byte_pos - first_byte_pos + 1
1488
            length = first_byte_pos + partial
1489
            data = get_random_data(partial)
1490
            args = {'content_type':'application/octet-stream',
1491
                    'content_range':'%s' %range}
1492
            if content_length:
1493
                args['content_length'] = content_length
1494

    
1495
            r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1496
                                      StringIO(data), **args)
1497
            status = r[0]
1498
            etag = r[1]['etag']
1499
            if partial < 0 or (instance_length and l <= last_byte_pos):
1500
                self.assertEqual(status, 202)
1501
            else:
1502
                self.assertEqual(status, 204)
1503
                #check modified object
1504
                content = self.client.retrieve_object(self.containers[0],
1505
                                                  self.obj[0]['name'])
1506
                self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1507
                self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1508
                self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1509
                self.assertEqual(etag, compute_md5_hash(content))
1510

    
1511
    def test_update_object_lt_blocksize(self):
1512
        self.test_update_object(10, 20, content_length=None)
1513

    
1514
    def test_update_object_gt_blocksize(self):
1515
        o = self.upload_random_data(self.containers[0], o_names[1],
1516
                                length=4*1024*1024+5)
1517
        c = self.containers[0]
1518
        o_name = o['name']
1519
        o_data = o['data']
1520
        first_byte_pos = 4*1024*1024+1
1521
        last_byte_pos = 4*1024*1024+4
1522
        l = last_byte_pos - first_byte_pos + 1
1523
        data = get_random_data(l)
1524
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1525
        self.client.update_object(c, o_name, StringIO(data), content_range=range)
1526
        content = self.client.retrieve_object(c, o_name)
1527
        self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1528
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1529
        self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1530

    
1531
    def test_update_object_divided_by_blocksize(self):
1532
        o = self.upload_random_data(self.containers[0], o_names[1],
1533
                                length=4*1024*1024+5)
1534
        c = self.containers[0]
1535
        o_name = o['name']
1536
        o_data = o['data']
1537
        first_byte_pos = 4*1024*1024
1538
        last_byte_pos = 5*1024*1024
1539
        l = last_byte_pos - first_byte_pos + 1
1540
        data = get_random_data(l)
1541
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1542
        self.client.update_object(c, o_name, StringIO(data), content_range=range)
1543
        content = self.client.retrieve_object(c, o_name)
1544
        self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1545
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1546
        self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1547

    
1548
    def test_update_object_no_content_length(self):
1549
        self.test_update_object(content_length = None)
1550

    
1551
    def test_update_object_invalid_content_length(self):
1552
        with AssertContentInvariant(self.client.retrieve_object,
1553
                                    self.containers[0], self.obj[0]['name']):
1554
            self.assert_raises_fault(400, self.test_update_object,
1555
                                     content_length = 1000)
1556

    
1557
    def _test_update_object_invalid_range(self):
1558
        with AssertContentInvariant(self.client.retrieve_object,
1559
                                    self.containers[0], self.obj[0]['name']):
1560
            self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1561

    
1562
    def _test_update_object_invalid_range_and_length(self):
1563
        with AssertContentInvariant(self.client.retrieve_object,
1564
                                    self.containers[0], self.obj[0]['name']):
1565
            self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1566
                                     -1)
1567

    
1568
    def test_update_object_invalid_range_with_no_content_length(self):
1569
        with AssertContentInvariant(self.client.retrieve_object,
1570
                                    self.containers[0], self.obj[0]['name']):
1571
            self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1572
                                     content_length = None)
1573

    
1574
    def test_update_object_out_of_limits(self):
1575
        with AssertContentInvariant(self.client.retrieve_object,
1576
                                    self.containers[0], self.obj[0]['name']):
1577
            l = len(self.obj[0]['data'])
1578
            self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1579

    
1580
    def test_append(self):
1581
        data = get_random_data(500)
1582
        headers = {}
1583
        self.client.update_object(self.containers[0], self.obj[0]['name'],
1584
                                  StringIO(data), content_length=500,
1585
                                  content_type='application/octet-stream')
1586

    
1587
        content = self.client.retrieve_object(self.containers[0],
1588
                                              self.obj[0]['name'])
1589
        self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1590
        self.assertEqual(content[:-500], self.obj[0]['data'])
1591

    
1592
    def test_update_with_chunked_transfer(self):
1593
        data = get_random_data(500)
1594
        dl = len(data)
1595
        fl = len(self.obj[0]['data'])
1596

    
1597
        self.client.update_object_using_chunks(self.containers[0],
1598
                                               self.obj[0]['name'],
1599
                                               StringIO(data),
1600
                                               offset=0,
1601
                                               content_type='application/octet-stream')
1602

    
1603
        #check modified object
1604
        content = self.client.retrieve_object(self.containers[0],
1605
                                              self.obj[0]['name'])
1606
        self.assertEqual(content[0:dl], data)
1607
        self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1608

    
1609
    def test_update_from_other_object(self):
1610
        c = self.containers[0]
1611
        src = o_names[0]
1612
        dest = 'object'
1613

    
1614
        source_data = self.client.retrieve_object(c, src)
1615
        source_meta = self.client.retrieve_object_metadata(c, src)
1616
        source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1617

    
1618
        #update zero length object
1619
        self.client.create_zero_length_object(c, dest)
1620
        source_object = '/%s/%s' % (c, src)
1621
        self.client.update_from_other_source(c, dest, source_object)
1622
        dest_data = self.client.retrieve_object(c, src)
1623
        dest_meta = self.client.retrieve_object_metadata(c, dest)
1624
        dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1625
        self.assertEqual(source_data, dest_data)
1626
        self.assertEqual(source_hash, dest_hash)
1627

    
1628
        #test append
1629
        self.client.update_from_other_source(c, dest, source_object)
1630
        content = self.client.retrieve_object(c, dest)
1631
        self.assertEqual(source_data * 2, content)
1632

    
1633
    def test_update_range_from_other_object(self):
1634
        c = self.containers[0]
1635
        dest = 'object'
1636

    
1637
        #test update range
1638
        src = self.obj[1]['name']
1639
        src_data = self.client.retrieve_object(c, src)
1640

    
1641
        #update zero length object
1642
        prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1643
        source_object = '/%s/%s' % (c, src)
1644
        first_byte_pos = 4*1024*1024+1
1645
        last_byte_pos = 4*1024*1024+4
1646
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1647
        self.client.update_from_other_source(c, dest, source_object,
1648
                                             content_range=range)
1649
        content = self.client.retrieve_object(c, dest)
1650
        self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1651
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1652
        self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1653

    
1654
    def test_update_hashes_from_other_object(self):
1655
        c = self.containers[0]
1656
        dest = 'object'
1657

    
1658
        #test update range
1659
        src_data = self.upload_random_data(c, o_names[0], length=1024*1024+10)['data']
1660

    
1661
        #update zero length object
1662
        prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1663
        source_object = '/%s/%s' % (c, o_names[0])
1664
        first_byte_pos = 4*1024*1024
1665
        last_byte_pos = 5*1024*1024
1666
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1667
        self.client.update_from_other_source(c, dest, source_object,
1668
                                             content_range=range)
1669
        content = self.client.retrieve_object(c, dest)
1670
        self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1671
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1672
        self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1673

    
1674

    
1675
    def test_update_zero_length_object(self):
1676
        c = self.containers[0]
1677
        o = 'object'
1678
        other = 'other'
1679
        zero = self.client.create_zero_length_object(c, o)
1680

    
1681
        data = get_random_data()
1682
        self.client.update_object(c, o, StringIO(data))
1683
        self.client.create_object(c, other, StringIO(data))
1684

    
1685
        self.assertEqual(self.client.retrieve_object(c, o),
1686
                         self.client.retrieve_object(c, other))
1687

    
1688
        self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1689
                         self.client.retrieve_object_hashmap(c, other)["hashes"])
1690

    
1691
class ObjectDelete(BaseTestCase):
1692
    def setUp(self):
1693
        BaseTestCase.setUp(self)
1694
        self.containers = ['c1', 'c2']
1695
        for c in self.containers:
1696
            self.client.create_container(c)
1697
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1698

    
1699
    def test_delete(self):
1700
        #perform delete object
1701
        self.client.delete_object(self.containers[0], self.obj['name'])[0]
1702

    
1703
    def test_delete_invalid(self):
1704
        #assert item not found
1705
        self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1706
                                 self.obj['name'])
1707

    
1708
class ListSharing(BaseTestCase):
1709
    def setUp(self):
1710
        BaseTestCase.setUp(self)
1711
        for i in range(2):
1712
            self.client.create_container('c%s' %i)
1713
        self.client.create_container('c')
1714
        for i in range(2):
1715
            self.upload_random_data('c1', 'o%s' %i)
1716
        accounts = OTHER_ACCOUNTS.copy()
1717
        self.o1_sharing_with = accounts.popitem()
1718
        self.o1_sharing = [self.o1_sharing_with[1]]
1719
        self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1720

    
1721
        l = []
1722
        for i in range(2):
1723
            l.append(accounts.popitem())
1724

    
1725
    def test_list_other_shared(self):
1726
        self.other = Pithos_Client(get_url(),
1727
                              self.o1_sharing_with[0],
1728
                              self.o1_sharing_with[1])
1729
        self.assertTrue(get_user() in self.other.list_shared_by_others())
1730

    
1731
    def test_list_my_shared(self):
1732
        my_shared_containers = self.client.list_containers(shared=True)
1733
        self.assertTrue('c1' in my_shared_containers)
1734
        self.assertTrue('c2' not in my_shared_containers)
1735

    
1736
        my_shared_objects = self.client.list_objects('c1', shared=True)
1737
        self.assertTrue('o1' in my_shared_objects)
1738
        self.assertTrue('o2' not in my_shared_objects)
1739

    
1740
class List(BaseTestCase):
1741
    def setUp(self):
1742
        BaseTestCase.setUp(self)
1743
        for i in range(1, 5):
1744
            c = 'c%s' % i
1745
            self.client.create_container(c)
1746
            for j in range(1, 3):
1747
                o = 'o%s' % j
1748
                self.upload_random_data(c, o)
1749
            if i < 3:
1750
                self.client.share_object(c, 'o1', ['papagian'], read=True)
1751
            if i%2 != 0:
1752
                self.client.publish_object(c, 'o2')
1753
    
1754
    def test_shared_public(self):
1755
        func, kwargs = self.client.list_containers, {'shared':True}
1756
        l = func(**kwargs)
1757
        self.assertEqual(l, ['c1', 'c2'])
1758
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1759
        
1760
        func, kwargs = self.client.list_containers, {'public':True}
1761
        l = func(**kwargs)
1762
        self.assertEqual(l, ['c1', 'c3'])
1763
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1764
        
1765
        func, kwargs = self.client.list_containers, {'shared':True, 'public':True}
1766
        l = func(**kwargs)
1767
        self.assertEqual(l, ['c1', 'c2', 'c3'])
1768
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1769
        
1770
        
1771
        func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True}
1772
        l = func(*args, **kwargs)
1773
        self.assertEqual(l, ['o1'])
1774
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1775
        
1776
        func, args, kwargs = self.client.list_objects, ['c1'], {'public':True}
1777
        l = func(*args, **kwargs)
1778
        self.assertEqual(l, ['o2'])
1779
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1780
        
1781
        func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True, 'public':True}
1782
        l = func(*args, **kwargs)
1783
        self.assertEqual(l, ['o1', 'o2'])
1784
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1785
        
1786
        
1787
        func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True}
1788
        l = func(*args, **kwargs)
1789
        self.assertEqual(l, ['o1'])
1790
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1791
        
1792
        func, args, kwargs = self.client.list_objects, ['c2'], {'public':True}
1793
        l = func(*args, **kwargs)
1794
        self.assertEqual(l, '')
1795
        self.assertEqual([], func(*args, format='json', **kwargs))
1796
        
1797
        func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True, 'public':True}
1798
        l = func(*args, **kwargs)
1799
        self.assertEqual(l, ['o1'])
1800
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1801
        
1802
        
1803
        func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True}
1804
        l = func(*args, **kwargs)
1805
        self.assertEqual(l, '')
1806
        self.assertEqual([], func(*args, format='json', **kwargs))
1807
        
1808
        func, args, kwargs = self.client.list_objects, ['c3'], {'public':True}
1809
        l = func(*args, **kwargs)
1810
        self.assertEqual(l, ['o2'])
1811
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1812
        
1813
        func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True, 'public':True}
1814
        l = func(*args, **kwargs)
1815
        self.assertEqual(l, ['o2'])
1816
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1817
        
1818
        
1819
        func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True}
1820
        l = func(*args, **kwargs)
1821
        self.assertEqual(l, '')
1822
        self.assertEqual([], func(*args, format='json', **kwargs))
1823
        
1824
        func, args, kwargs = self.client.list_objects, ['c4'], {'public':True}
1825
        l = func(*args, **kwargs)
1826
        self.assertEqual(l, '')
1827
        self.assertEqual([], func(*args, format='json', **kwargs))
1828
        
1829
        func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True, 'public':True}
1830
        l = func(*args, **kwargs)
1831
        self.assertEqual(l, '')
1832
        self.assertEqual([], func(*args, format='json', **kwargs))
1833

    
1834
class TestGreek(BaseTestCase):
1835
    def test_create_container(self):
1836
        self.client.create_container('φάκελος')
1837
        self.assert_container_exists('φάκελος')
1838

    
1839
        self.assertTrue('φάκελος' in self.client.list_containers())
1840

    
1841
    def test_create_object(self):
1842
        self.client.create_container('φάκελος')
1843
        self.upload_random_data('φάκελος', 'αντικείμενο')
1844

    
1845
        self.assert_object_exists('φάκελος', 'αντικείμενο')
1846
        self.assertTrue('αντικείμενο' in self.client.list_objects('φάκελος'))
1847

    
1848
    def test_copy_object(self):
1849
        src_container = 'φάκελος'
1850
        src_object = 'αντικείμενο'
1851
        dest_container = 'αντίγραφα'
1852
        dest_object = 'ασφαλές-αντίγραφο'
1853

    
1854
        self.client.create_container(src_container)
1855
        self.upload_random_data(src_container, src_object)
1856

    
1857
        self.client.create_container(dest_container)
1858
        self.client.copy_object(src_container, src_object, dest_container,
1859
                                dest_object)
1860

    
1861
        self.assert_object_exists(src_container, src_object)
1862
        self.assert_object_exists(dest_container, dest_object)
1863
        self.assertTrue(dest_object in self.client.list_objects(dest_container))
1864

    
1865
    def test_move_object(self):
1866
        src_container = 'φάκελος'
1867
        src_object = 'αντικείμενο'
1868
        dest_container = 'αντίγραφα'
1869
        dest_object = 'ασφαλές-αντίγραφο'
1870

    
1871
        self.client.create_container(src_container)
1872
        self.upload_random_data(src_container, src_object)
1873

    
1874
        self.client.create_container(dest_container)
1875
        self.client.move_object(src_container, src_object, dest_container,
1876
                                dest_object)
1877

    
1878
        self.assert_object_not_exists(src_container, src_object)
1879
        self.assert_object_exists(dest_container, dest_object)
1880
        self.assertTrue(dest_object in self.client.list_objects(dest_container))
1881

    
1882
    def test_delete_object(self):
1883
        self.client.create_container('φάκελος')
1884
        self.upload_random_data('φάκελος', 'αντικείμενο')
1885
        self.assert_object_exists('φάκελος', 'αντικείμενο')
1886

    
1887
        self.client.delete_object('φάκελος', 'αντικείμενο')
1888
        self.assert_object_not_exists('φάκελος', 'αντικείμενο')
1889
        self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
1890

    
1891
    def test_delete_container(self):
1892
        self.client.create_container('φάκελος')
1893
        self.assert_container_exists('φάκελος')
1894

    
1895
        self.client.delete_container('φάκελος')
1896
        self.assert_container_not_exists('φάκελος')
1897
        self.assertTrue('φάκελος' not in self.client.list_containers())
1898

    
1899
    def test_account_meta(self):
1900
        meta = {'ποιότητα':'ΑΑΑ'}
1901
        self.client.update_account_metadata(**meta)
1902
        meta = self.client.retrieve_account_metadata(restricted=True)
1903
        self.assertTrue('ποιότητα' in meta.keys())
1904
        self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1905

    
1906
    def test_container_meta(self):
1907
        meta = {'ποιότητα':'ΑΑΑ'}
1908
        self.client.create_container('φάκελος', meta=meta)
1909

    
1910
        meta = self.client.retrieve_container_metadata('φάκελος', restricted=True)
1911
        self.assertTrue('ποιότητα' in meta.keys())
1912
        self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1913

    
1914
    def test_object_meta(self):
1915
        self.client.create_container('φάκελος')
1916
        meta = {'ποιότητα':'ΑΑΑ'}
1917
        self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
1918

    
1919
        meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
1920
                                                    restricted=True)
1921
        self.assertTrue('ποιότητα' in meta.keys())
1922
        self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
1923

    
1924
    def test_list_meta_filtering(self):
1925
        self.client.create_container('φάκελος')
1926
        meta = {'ποιότητα':'ΑΑΑ'}
1927
        self.upload_random_data('φάκελος', 'ο1', **meta)
1928
        self.upload_random_data('φάκελος', 'ο2')
1929
        self.upload_random_data('φάκελος', 'ο3')
1930

    
1931
        meta = {'ποσότητα':'μεγάλη'}
1932
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1933
        objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
1934
        self.assertEquals(objects, ['ο1', 'ο2'])
1935

    
1936
        objects = self.client.list_objects('φάκελος', meta='!ποιότητα')
1937
        self.assertEquals(objects, ['ο2', 'ο3'])
1938

    
1939
        objects = self.client.list_objects('φάκελος', meta='!ποιότητα, !ποσότητα')
1940
        self.assertEquals(objects, ['ο3'])
1941

    
1942
        meta = {'ποιότητα':'ΑΒ'}
1943
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1944
        objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
1945
        self.assertEquals(objects, ['ο1'])
1946
        objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
1947
        self.assertEquals(objects, ['ο2'])
1948

    
1949
        meta = {'έτος':'2011'}
1950
        self.client.update_object_metadata('φάκελος', 'ο3', **meta)
1951
        meta = {'έτος':'2012'}
1952
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
1953
        objects = self.client.list_objects('φάκελος', meta='έτος<2012')
1954
        self.assertEquals(objects, ['ο3'])
1955
        objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
1956
        self.assertEquals(objects, ['ο2', 'ο3'])
1957
        objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
1958
        self.assertEquals(objects, '')
1959

    
1960
    def test_groups(self):
1961
        #create a group
1962
        groups = {'σεφς':'chazapis,διογένης'}
1963
        self.client.set_account_groups(**groups)
1964
        groups.update(self.initial_groups)
1965
        self.assertEqual(groups['σεφς'],
1966
                         self.client.retrieve_account_groups()['σεφς'])
1967

    
1968
        #check read access
1969
        self.client.create_container('φάκελος')
1970
        o = self.upload_random_data('φάκελος', 'ο1')
1971
        self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
1972
        chef = Pithos_Client(get_url(),
1973
                            '0009',
1974
                            'διογένης')
1975
        self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
1976
                                     'φάκελος', 'ο1', account=get_user())
1977

    
1978
        #check write access
1979
        self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
1980
        new_data = get_random_data()
1981
        self.assert_not_raises_fault(403, chef.update_object,
1982
                                     'φάκελος', 'ο1', StringIO(new_data),
1983
                                     account=get_user())
1984

    
1985
        server_data = self.client.retrieve_object('φάκελος', 'ο1')
1986
        self.assertEqual(server_data[:len(o['data'])], o['data'])
1987
        self.assertEqual(server_data[len(o['data']):], new_data)
1988

    
1989
    def test_manifestation(self):
1990
        self.client.create_container('κουβάς')
1991
        prefix = 'μέρη/'
1992
        data = ''
1993
        for i in range(5):
1994
            part = '%s%d' %(prefix, i)
1995
            o = self.upload_random_data('κουβάς', part)
1996
            data += o['data']
1997

    
1998
        self.client.create_container('φάκελος')
1999
        manifest = '%s/%s' %('κουβάς', prefix)
2000
        self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
2001

    
2002
        self.assert_object_exists('φάκελος', 'άπαντα')
2003
        self.assertEqual(data, self.client.retrieve_object('φάκελος',
2004
                                                           'άπαντα'))
2005

    
2006
        #wrong manifestation
2007
        self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
2008
        self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
2009

    
2010
    def test_update_from_another_object(self):
2011
        self.client.create_container('κουβάς')
2012
        src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
2013
        initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
2014
        source_object = '/%s/%s' % ('κουβάς', 'πηγή')
2015
        self.client.update_from_other_source('κουβάς', 'νέο', source_object)
2016

    
2017
        self.assertEqual(
2018
            self.client.retrieve_object('κουβάς', 'νέο'),
2019
            '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
2020

    
2021
class TestPermissions(BaseTestCase):
2022
    def setUp(self):
2023
        BaseTestCase.setUp(self)
2024

    
2025
        #create a group
2026
        self.authorized = ['chazapis', 'verigak', 'gtsouk']
2027
        groups = {'pithosdev':','.join(self.authorized)}
2028
        self.client.set_account_groups(**groups)
2029

    
2030
        self.container = 'c'
2031
        self.object = 'o'
2032
        self.client.create_container(self.container)
2033
        self.upload_random_data(self.container, self.object)
2034
        self.upload_random_data(self.container, self.object+'/')
2035
        self.upload_random_data(self.container, self.object+'/a')
2036
        self.upload_random_data(self.container, self.object+'a')
2037
        self.upload_random_data(self.container, self.object+'a/')
2038
        self.dir_content_types = ('application/directory', 'application/folder')
2039

    
2040
    def assert_read(self, authorized=[], any=False, depth=0):
2041
        for token, account in OTHER_ACCOUNTS.items():
2042
            cl = Pithos_Client(get_url(), token, account)
2043
            if account in authorized or any:
2044
                self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2045
                                             self.container, self.object,
2046
                                             account=get_user())
2047
            else:
2048
                self.assert_raises_fault(403, cl.retrieve_object_metadata,
2049
                                         self.container, self.object,
2050
                                         account=get_user())
2051

    
2052
        #check inheritance
2053
        meta = self.client.retrieve_object_metadata(self.container, self.object)
2054
        type = meta['content-type']
2055
        derivatives = self.client.list_objects(self.container, prefix=self.object)
2056
        #exclude the self.object
2057
        del derivatives[derivatives.index(self.object)]
2058
        for o in derivatives:
2059
            for token, account in OTHER_ACCOUNTS.items():
2060
                cl = Pithos_Client(get_url(), token, account)
2061
                prefix = self.object if self.object.endswith('/') else self.object+'/'
2062
                if (account in authorized or any) and \
2063
                (type in self.dir_content_types) and \
2064
                o.startswith(prefix):
2065
                    self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2066
                                             self.container, o, account=get_user())
2067
                else:
2068
                    self.assert_raises_fault(403, cl.retrieve_object_metadata,
2069
                                         self.container, o, account=get_user())
2070

    
2071
    def assert_write(self, authorized=[], any=False):
2072
        o_data = self.client.retrieve_object(self.container, self.object)
2073
        for token, account in OTHER_ACCOUNTS.items():
2074
            cl = Pithos_Client(get_url(), token, account)
2075
            new_data = get_random_data()
2076
            if account in authorized or any:
2077
                # test write access
2078
                self.assert_not_raises_fault(403, cl.update_object,
2079
                                             self.container, self.object, StringIO(new_data),
2080
                                             account=get_user())
2081
                try:
2082
                    # test read access
2083
                    server_data = cl.retrieve_object(self.container, self.object, account=get_user())
2084
                    self.assertEqual(o_data, server_data[:len(o_data)])
2085
                    self.assertEqual(new_data, server_data[len(o_data):])
2086
                    o_data = server_data
2087
                except Fault, f:
2088
                    self.failIf(f.status == 403)
2089
            else:
2090
                self.assert_raises_fault(403, cl.update_object,
2091
                                             self.container, self.object, StringIO(new_data),
2092
                                             account=get_user())
2093
        #check inheritance
2094
        meta = self.client.retrieve_object_metadata(self.container, self.object)
2095
        type = meta['content-type']
2096
        derivatives = self.client.list_objects(self.container, prefix=self.object)
2097
        #exclude the object
2098
        del derivatives[derivatives.index(self.object)]
2099
        for o in derivatives:
2100
            for token, account in OTHER_ACCOUNTS.items():
2101
                prefix = self.object if self.object.endswith('/') else self.object+'/'
2102
                cl = Pithos_Client(get_url(), token, account)
2103
                new_data = get_random_data()
2104
                if (account in authorized or any) and \
2105
                (type in self.dir_content_types) and \
2106
                o.startswith(prefix):
2107
                    # test write access
2108
                    self.assert_not_raises_fault(403, cl.update_object,
2109
                                                 self.container, o,
2110
                                                 StringIO(new_data),
2111
                                                 account=get_user())
2112
                    try:
2113
                        server_data = cl.retrieve_object(self.container, o, account=get_user())
2114
                        self.assertEqual(new_data, server_data[-len(new_data):])
2115
                    except Fault, f:
2116
                        self.failIf(f.status == 403)
2117
                else:
2118
                    self.assert_raises_fault(403, cl.update_object,
2119
                                                 self.container, o,
2120
                                                 StringIO(new_data),
2121
                                                 account=get_user())
2122

    
2123
    def test_group_read(self):
2124
        self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2125
        self.assert_read(authorized=self.authorized)
2126

    
2127
    def test_read_many(self):
2128
        self.client.share_object(self.container, self.object, self.authorized)
2129
        self.assert_read(authorized=self.authorized)
2130

    
2131
    def test_read_by_everyone(self):
2132
        self.client.share_object(self.container, self.object, ['*'])
2133
        self.assert_read(any=True)
2134

    
2135
    def test_read_directory(self):
2136
        for type in self.dir_content_types:
2137
            #change content type
2138
            self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2139
            self.client.share_object(self.container, self.object, ['*'])
2140
            self.assert_read(any=True)
2141
            self.client.share_object(self.container, self.object, self.authorized)
2142
            self.assert_read(authorized=self.authorized)
2143
            self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2144
            self.assert_read(authorized=self.authorized)
2145

    
2146
    def test_group_write(self):
2147
        self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2148
        self.assert_write(authorized=self.authorized)
2149

    
2150
    def test_write_many(self):
2151
        self.client.share_object(self.container, self.object, self.authorized, read=False)
2152
        self.assert_write(authorized=self.authorized)
2153

    
2154
    def test_write_by_everyone(self):
2155
        self.client.share_object(self.container, self.object, ['*'], read=False)
2156
        self.assert_write(any=True)
2157

    
2158
    def test_write_directory(self):
2159
        dir_content_types = ('application/directory', 'application/foler')
2160
        for type in dir_content_types:
2161
            #change content type
2162
            self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2163
            self.client.share_object(self.container, self.object, ['*'], read=False)
2164
            self.assert_write(any=True)
2165
            self.client.share_object(self.container, self.object, self.authorized, read=False)
2166
            self.assert_write(authorized=self.authorized)
2167
            self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2168
            self.assert_write(authorized=self.authorized)
2169

    
2170
    def test_shared_listing(self):
2171
        self.client.share_object(self.container, self.object, self.authorized)
2172

    
2173
        my_shared_containers = self.client.list_containers(shared=True)
2174
        self.assertEqual(['c'], my_shared_containers)
2175
        my_shared_objects = self.client.list_objects('c', shared=True)
2176
        self.assertEqual(['o'], my_shared_objects)
2177

    
2178
        dir_content_types = ('application/directory', 'application/foler')
2179
        for type in dir_content_types:
2180
            #change content type
2181
            self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2182
            my_shared_objects = self.client.list_objects('c', shared=True)
2183
            self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2184

    
2185
        for token, account in OTHER_ACCOUNTS.items():
2186
            if account in self.authorized:
2187
                self.other = Pithos_Client(get_url(), token, account)
2188
                self.assertTrue(get_user() in self.other.list_shared_by_others())
2189

    
2190
class TestPublish(BaseTestCase):
2191
    def test_publish(self):
2192
        self.client.create_container('c')
2193
        o_data = self.upload_random_data('c', 'o')['data']
2194
        self.client.publish_object('c', 'o')
2195
        meta = self.client.retrieve_object_metadata('c', 'o')
2196
        self.assertTrue('x-object-public' in meta)
2197
        url = meta['x-object-public']
2198

    
2199
        p = urlparse(get_url())
2200
        if p.scheme == 'http':
2201
            conn = HTTPConnection(p.netloc)
2202
        elif p.scheme == 'https':
2203
            conn = HTTPSConnection(p.netloc)
2204
        else:
2205
            raise Exception('Unknown URL scheme')
2206

    
2207
        conn.request('GET', url)
2208
        resp = conn.getresponse()
2209
        length = resp.getheader('content-length', None)
2210
        data = resp.read(length)
2211
        self.assertEqual(o_data, data)
2212

    
2213
class TestPolicies(BaseTestCase):
2214
    def test_none_versioning(self):
2215
        self.client.create_container('c', policies={'versioning':'none'})
2216
        o = self.upload_random_data('c', 'o')
2217
        meta = self.client.retrieve_object_metadata('c', 'o')
2218
        v = meta['x-object-version']
2219
        more_data = get_random_data()
2220
        self.client.update_object('c', 'o', StringIO(more_data))
2221
        vlist = self.client.retrieve_object_versionlist('c', 'o')
2222
        self.assert_raises_fault(404, self.client.retrieve_object_version,
2223
                                 'c', 'o', v)
2224
        data = self.client.retrieve_object('c', 'o')
2225
        end = len(o['data'])
2226
        self.assertEqual(data[:end], o['data'])
2227
        self.assertEqual(data[end:], more_data)
2228

    
2229
    def test_quota(self):
2230
        self.client.create_container('c', policies={'quota':'1'})
2231
        meta = self.client.retrieve_container_metadata('c')
2232
        self.assertEqual(meta['x-container-policy-quota'], '1')
2233
        self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2234
                                 length=1024*1024+1)
2235

    
2236
    def test_quota_none(self):
2237
        self.client.create_container('c', policies={'quota':'0'})
2238
        meta = self.client.retrieve_container_metadata('c')
2239
        self.assertEqual(meta['x-container-policy-quota'], '0')
2240
        self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2241
                                 length=1024*1024+1)
2242

    
2243
class AssertUUidInvariant(object):
2244
    def __init__(self, callable, *args, **kwargs):
2245
        self.callable = callable
2246
        self.args = args
2247
        self.kwargs = kwargs
2248

    
2249
    def __enter__(self):
2250
        self.map = self.callable(*self.args, **self.kwargs)
2251
        assert('x-object-uuid' in self.map)
2252
        self.uuid = self.map['x-object-uuid']
2253
        return self.map
2254

    
2255
    def __exit__(self, type, value, tb):
2256
        map = self.callable(*self.args, **self.kwargs)
2257
        assert('x-object-uuid' in self.map)
2258
        uuid = map['x-object-uuid']
2259
        assert(uuid == self.uuid)
2260

    
2261
class AssertMappingInvariant(object):
2262
    def __init__(self, callable, *args, **kwargs):
2263
        self.callable = callable
2264
        self.args = args
2265
        self.kwargs = kwargs
2266

    
2267
    def __enter__(self):
2268
        self.map = self.callable(*self.args, **self.kwargs)
2269
        return self.map
2270

    
2271
    def __exit__(self, type, value, tb):
2272
        map = self.callable(*self.args, **self.kwargs)
2273
        for k, v in self.map.items():
2274
            if is_date(v):
2275
                continue
2276
            #print '#', k, v, map[k]
2277
            assert(k in map)
2278
            assert v == map[k]
2279

    
2280
class AssertContentInvariant(object):
2281
    def __init__(self, callable, *args, **kwargs):
2282
        self.callable = callable
2283
        self.args = args
2284
        self.kwargs = kwargs
2285

    
2286
    def __enter__(self):
2287
        self.content = self.callable(*self.args, **self.kwargs)[2]
2288
        return self.content
2289

    
2290
    def __exit__(self, type, value, tb):
2291
        content = self.callable(*self.args, **self.kwargs)[2]
2292
        assert self.content == content
2293

    
2294
def get_content_splitted(response):
2295
    if response:
2296
        return response.content.split('\n')
2297

    
2298
def compute_md5_hash(data):
2299
    md5 = hashlib.md5()
2300
    offset = 0
2301
    md5.update(data)
2302
    return md5.hexdigest().lower()
2303

    
2304
def compute_block_hash(data, algorithm):
2305
    h = hashlib.new(algorithm)
2306
    h.update(data.rstrip('\x00'))
2307
    return h.hexdigest()
2308

    
2309
def get_random_data(length=500):
2310
    char_set = string.ascii_uppercase + string.digits
2311
    return ''.join(random.choice(char_set) for x in xrange(length))
2312

    
2313
def is_date(date):
2314
    MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2315
    __D = r'(?P<day>\d{2})'
2316
    __D2 = r'(?P<day>[ \d]\d)'
2317
    __M = r'(?P<mon>\w{3})'
2318
    __Y = r'(?P<year>\d{4})'
2319
    __Y2 = r'(?P<year>\d{2})'
2320
    __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2321
    RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2322
    RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2323
    ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2324
    for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2325
        m = regex.match(date)
2326
        if m is not None:
2327
            return True
2328
    return False
2329

    
2330
o_names = ['kate.jpg',
2331
           'kate_beckinsale.jpg',
2332
           'How To Win Friends And Influence People.pdf',
2333
           'moms_birthday.jpg',
2334
           'poodle_strut.mov',
2335
           'Disturbed - Down With The Sickness.mp3',
2336
           'army_of_darkness.avi',
2337
           'the_mad.avi',
2338
           'photos/animals/dogs/poodle.jpg',
2339
           'photos/animals/dogs/terrier.jpg',
2340
           'photos/animals/cats/persian.jpg',
2341
           'photos/animals/cats/siamese.jpg',
2342
           'photos/plants/fern.jpg',
2343
           'photos/plants/rose.jpg',
2344
           'photos/me.jpg']
2345

    
2346

    
2347
def main():
2348
    if get_user() == 'test':
2349
        unittest.main(module='pithos.tools.test')
2350
    else:
2351
        print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2352

    
2353

    
2354
if __name__ == "__main__":
2355
    main()
2356