Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-tools / pithos / tools / test.py @ 07867f70

History | View | Annotate | Download (102.7 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_shared(self):
543
        self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
544
        objs = self.client.list_objects(self.container[0], shared=True)
545
        self.assertEqual(objs, [self.obj[0]['name']])
546
        
547
        # create child object
548
        self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
549
        objs = self.client.list_objects(self.container[0], shared=True)
550
        self.assertEqual(objs, [self.obj[0]['name']])
551
        
552
        # test inheritance
553
        self.client.create_folder(self.container[1], 'folder')
554
        self.client.share_object(self.container[1], 'folder', ('*',))
555
        self.upload_random_data(self.container[1], 'folder/object')
556
        objs = self.client.list_objects(self.container[1], shared=True)
557
        self.assertEqual(objs, ['folder', 'folder/object'])
558
    
559
    def test_list_public(self):
560
        self.client.publish_object(self.container[0], self.obj[0]['name'])
561
        objs = self.client.list_objects(self.container[0], public=True)
562
        self.assertEqual(objs, [self.obj[0]['name']])
563
        
564
        # create child object
565
        self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
566
        objs = self.client.list_objects(self.container[0], public=True)
567
        self.assertEqual(objs, [self.obj[0]['name']])
568
        
569
        # test inheritance
570
        self.client.create_folder(self.container[1], 'folder')
571
        self.client.publish_object(self.container[1], 'folder')
572
        self.upload_random_data(self.container[1], 'folder/object')
573
        objs = self.client.list_objects(self.container[1], public=True)
574
        self.assertEqual(objs, ['folder'])
575
    
576
    def test_list_shared_public(self):
577
        self.client.share_object(self.container[0], self.obj[0]['name'], ('*',))
578
        self.client.publish_object(self.container[0], self.obj[1]['name'])
579
        objs = self.client.list_objects(self.container[0], shared=True, public=True)
580
        self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
581
        
582
        # create child object
583
        self.upload_random_data(self.container[0], strnextling(self.obj[0]['name']))
584
        self.upload_random_data(self.container[0], strnextling(self.obj[1]['name']))
585
        objs = self.client.list_objects(self.container[0], shared=True, public=True)
586
        self.assertEqual(objs, [self.obj[0]['name'], self.obj[1]['name']])
587
        
588
        # test inheritance
589
        self.client.create_folder(self.container[1], 'folder1')
590
        self.client.share_object(self.container[1], 'folder1', ('*',))
591
        self.upload_random_data(self.container[1], 'folder1/object')
592
        self.client.create_folder(self.container[1], 'folder2')
593
        self.client.publish_object(self.container[1], 'folder2')
594
        o = self.upload_random_data(self.container[1], 'folder2/object')
595
        objs = self.client.list_objects(self.container[1], shared=True, public=True)
596
        self.assertEqual(objs, ['folder1', 'folder1/object', 'folder2'])
597
    
598
    def test_list_objects(self):
599
        objects = self.client.list_objects(self.container[0])
600
        l = [elem['name'] for elem in self.obj[:8]]
601
        l.sort()
602
        self.assertEqual(objects, l)
603

    
604
    def test_list_objects_containing_slash(self):
605
        self.client.create_container('test')
606
        self.upload_random_data('test', '/objectname')
607

    
608
        objects = self.client.list_objects('test')
609
        self.assertEqual(objects, ['/objectname'])
610

    
611
        objects = self.client.list_objects('test', format='json')
612
        self.assertEqual(objects[0]['name'], '/objectname')
613

    
614
        objects = self.client.list_objects('test', format='xml')
615
        self.assert_extended(objects, 'xml', 'object')
616
        node_name = objects.getElementsByTagName('name')[0]
617
        self.assertEqual(node_name.firstChild.data, '/objectname')
618

    
619
    def test_list_objects_with_limit_marker(self):
620
        objects = self.client.list_objects(self.container[0], limit=2)
621
        l = [elem['name'] for elem in self.obj[:8]]
622
        l.sort()
623
        self.assertEqual(objects, l[:2])
624

    
625
        markers = ['How To Win Friends And Influence People.pdf',
626
                   'moms_birthday.jpg']
627
        limit = 4
628
        for m in markers:
629
            objects = self.client.list_objects(self.container[0], limit=limit,
630
                                               marker=m)
631
            l = [elem['name'] for elem in self.obj[:8]]
632
            l.sort()
633
            start = l.index(m) + 1
634
            end = start + limit
635
            end = end if len(l) >= end else len(l)
636
            self.assertEqual(objects, l[start:end])
637

    
638
    #takes too long
639
    def _test_list_limit_exceeds(self):
640
        self.client.create_container('pithos')
641

    
642
        for i in range(10001):
643
            self.client.create_zero_length_object('pithos', i)
644

    
645
        self.assertEqual(10000, len(self.client.list_objects('pithos')))
646

    
647
    def test_list_empty_params(self):
648
        objects = self.client.get('/%s/%s' % (get_user(), self.container[0]))[2]
649
        if objects:
650
            objects = objects.strip().split('\n')
651
        self.assertEqual(objects,
652
                         self.client.list_objects(self.container[0]))
653

    
654
    def test_list_pseudo_hierarchical_folders(self):
655
        objects = self.client.list_objects(self.container[1], prefix='photos',
656
                                           delimiter='/')
657
        self.assertEquals(['photos/animals/', 'photos/me.jpg',
658
                           'photos/plants/'], objects)
659

    
660
        objects = self.client.list_objects(self.container[1],
661
                                           prefix='photos/animals',
662
                                           delimiter='/')
663
        l = ['photos/animals/cats/', 'photos/animals/dogs/']
664
        self.assertEquals(l, objects)
665

    
666
        objects = self.client.list_objects(self.container[1], path='photos')
667
        self.assertEquals(['photos/me.jpg'], objects)
668

    
669
    def test_extended_list_json(self):
670
        objects = self.client.list_objects(self.container[1], format='json',
671
                                           limit=2, prefix='photos/animals',
672
                                           delimiter='/')
673
        self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
674
        self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
675

    
676
    def test_extended_list_xml(self):
677
        xml = self.client.list_objects(self.container[1], format='xml', limit=4,
678
                                       prefix='photos', delimiter='/')
679
        self.assert_extended(xml, 'xml', 'object', size=4)
680
        dirs = xml.getElementsByTagName('subdir')
681
        self.assertEqual(len(dirs), 2)
682
        self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
683
        self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
684

    
685
        objects = xml.getElementsByTagName('name')
686
        self.assertEqual(len(objects), 1)
687
        self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
688

    
689
    def test_list_meta_double_matching(self):
690
        meta = {'quality':'aaa', 'stock':'true'}
691
        self.client.update_object_metadata(self.container[0],
692
                                           self.obj[0]['name'], **meta)
693
        obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
694
        self.assertEqual(len(obj), 1)
695
        self.assertTrue(obj, self.obj[0]['name'])
696

    
697
    def test_list_using_meta(self):
698
        meta = {'quality':'aaa'}
699
        for o in self.obj[:2]:
700
            self.client.update_object_metadata(self.container[0], o['name'],
701
                                               **meta)
702
        meta = {'stock':'true'}
703
        for o in self.obj[3:5]:
704
            self.client.update_object_metadata(self.container[0], o['name'],
705
                                               **meta)
706

    
707
        obj = self.client.list_objects(self.container[0], meta='Quality')
708
        self.assertEqual(len(obj), 2)
709
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
710

    
711
        # test case insensitive
712
        obj = self.client.list_objects(self.container[0], meta='quality')
713
        self.assertEqual(len(obj), 2)
714
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
715

    
716
        # test multiple matches
717
        obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
718
        self.assertEqual(len(obj), 4)
719
        self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
720

    
721
        # test non 1-1 multiple match
722
        obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
723
        self.assertEqual(len(obj), 2)
724
        self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
725

    
726
    def test_if_modified_since(self):
727
        t = datetime.datetime.utcnow()
728
        t2 = t - datetime.timedelta(minutes=10)
729

    
730
        #add a new object
731
        self.upload_random_data(self.container[0], o_names[0])
732

    
733
        for f in DATE_FORMATS:
734
            past = t2.strftime(f)
735
            try:
736
                o = self.client.list_objects(self.container[0],
737
                                            if_modified_since=past)
738
                self.assertEqual(o,
739
                                 self.client.list_objects(self.container[0]))
740
            except Fault, f:
741
                self.failIf(f.status == 304) #fail if not modified
742

    
743
    def test_if_modified_since_invalid_date(self):
744
        headers = {'if-modified-since':''}
745
        o = self.client.list_objects(self.container[0], if_modified_since='')
746
        self.assertEqual(o, self.client.list_objects(self.container[0]))
747

    
748
    def test_if_not_modified_since(self):
749
        now = datetime.datetime.utcnow()
750
        since = now + datetime.timedelta(1)
751

    
752
        for f in DATE_FORMATS:
753
            args = {'if_modified_since':'%s' %since.strftime(f)}
754

    
755
            #assert not modified
756
            self.assert_raises_fault(304, self.client.list_objects,
757
                                     self.container[0], **args)
758

    
759
    def test_if_unmodified_since(self):
760
        now = datetime.datetime.utcnow()
761
        since = now + datetime.timedelta(1)
762

    
763
        for f in DATE_FORMATS:
764
            obj = self.client.list_objects(self.container[0],
765
                                           if_unmodified_since=since.strftime(f))
766

    
767
            #assert unmodified
768
            self.assertEqual(obj, self.client.list_objects(self.container[0]))
769

    
770
    def test_if_unmodified_since_precondition_failed(self):
771
        t = datetime.datetime.utcnow()
772
        t2 = t - datetime.timedelta(minutes=10)
773

    
774
        #add a new container
775
        self.client.create_container('dummy')
776

    
777
        for f in DATE_FORMATS:
778
            past = t2.strftime(f)
779

    
780
            args = {'if_unmodified_since':'%s' %past}
781

    
782
            #assert precondition failed
783
            self.assert_raises_fault(412, self.client.list_objects,
784
                                     self.container[0], **args)
785

    
786
class ContainerPut(BaseTestCase):
787
    def setUp(self):
788
        BaseTestCase.setUp(self)
789
        self.containers = ['c1', 'c2']
790

    
791
    def test_create(self):
792
        self.client.create_container(self.containers[0])
793
        containers = self.client.list_containers()
794
        self.assertTrue(self.containers[0] in containers)
795
        self.assert_container_exists(self.containers[0])
796

    
797
    def test_create_twice(self):
798
        self.client.create_container(self.containers[0])
799
        self.assertTrue(not self.client.create_container(self.containers[0]))
800

    
801
    def test_quota(self):
802
        self.client.create_container(self.containers[0])
803

    
804
        policy = {'quota':100}
805
        self.client.set_container_policies('c1', **policy)
806

    
807
        meta = self.client.retrieve_container_metadata('c1')
808
        self.assertTrue('x-container-policy-quota' in meta)
809
        self.assertEqual(meta['x-container-policy-quota'], '100')
810

    
811
        args = ['c1', 'o1']
812
        kwargs = {'length':101}
813
        self.assert_raises_fault(413, self.upload_random_data, *args, **kwargs)
814

    
815
        #reset quota
816
        policy = {'quota':0}
817
        self.client.set_container_policies('c1', **policy)
818

    
819
class ContainerPost(BaseTestCase):
820
    def setUp(self):
821
        BaseTestCase.setUp(self)
822
        self.container = 'apples'
823
        self.client.create_container(self.container)
824

    
825
    def test_update_meta(self):
826
        meta = {'test':'test33',
827
                'tost':'tost22'}
828
        self.client.update_container_metadata(self.container, **meta)
829
        headers = self.client.retrieve_container_metadata(self.container)
830
        for k,v in meta.items():
831
            k = 'x-container-meta-%s' % k
832
            self.assertTrue(headers[k])
833
            self.assertEqual(headers[k], v)
834

    
835
class ContainerDelete(BaseTestCase):
836
    def setUp(self):
837
        BaseTestCase.setUp(self)
838
        self.containers = ['c1', 'c2']
839
        for c in self.containers:
840
            self.client.create_container(c)
841

    
842
    def test_delete(self):
843
        status = self.client.delete_container(self.containers[0])[0]
844
        self.assertEqual(status, 204)
845

    
846
    def test_delete_non_empty(self):
847
        self.upload_random_data(self.containers[1], o_names[0])
848
        self.assert_raises_fault(409, self.client.delete_container,
849
                                 self.containers[1])
850

    
851
    def test_delete_invalid(self):
852
        self.assert_raises_fault(404, self.client.delete_container, 'c3')
853

    
854
class ObjectGet(BaseTestCase):
855
    def setUp(self):
856
        BaseTestCase.setUp(self)
857
        self.containers = ['c1', 'c2']
858
        #create some containers
859
        for c in self.containers:
860
            self.client.create_container(c)
861

    
862
        #upload a file
863
        names = ('obj1', 'obj2')
864
        self.objects = []
865
        for n in names:
866
            self.objects.append(self.upload_random_data(self.containers[1], n))
867

    
868
    def test_versions(self):
869
        c = self.containers[1]
870
        o = self.objects[0]
871
        b = self.client.retrieve_object_versionlist(c, o['name'])['versions']
872
        self.assert_versionlist_structure(b)
873

    
874
        #update meta
875
        meta = {'quality':'AAA', 'stock':True}
876
        self.client.update_object_metadata(c, o['name'], **meta)
877

    
878
        a = self.client.retrieve_object_versionlist(c, o['name'])['versions']
879
        self.assert_versionlist_structure(a)
880
        self.assertEqual(len(b)+1, len(a))
881
        self.assertEqual(b, a[:-1])
882

    
883
        #get exact previous version metadata
884
        v = a[-2][0]
885
        v_meta = self.client.retrieve_object_metadata(c, o['name'],
886
                                                      restricted=True,
887
                                                      version=v)
888
        for k in meta.keys():
889
            self.assertTrue(k not in v_meta)
890

    
891
        #update obejct
892
        data = get_random_data()
893
        self.client.update_object(c, o['name'], StringIO(data))
894

    
895
        aa = self.client.retrieve_object_versionlist(c, o['name'])['versions']
896
        self.assert_versionlist_structure(aa)
897
        self.assertEqual(len(a)+1, len(aa))
898
        self.assertEqual(a, aa[:-1])
899

    
900
        #get exact previous version
901
        v = aa[-3][0]
902
        v_data = self.client.retrieve_object_version(c, o['name'], version=v)
903
        self.assertEqual(o['data'], v_data)
904
        self.assertEqual(self.client.retrieve_object(c, o['name']),
905
                         '%s%s' %(v_data, data))
906

    
907
    def test_get(self):
908
        #perform get
909
        o = self.client.retrieve_object(self.containers[1],
910
                                        self.objects[0]['name'],
911
                                        self.objects[0]['meta'])
912
        self.assertEqual(o, self.objects[0]['data'])
913

    
914
    def test_objects_with_trailing_spaces(self):
915
        self.client.create_container('test')
916
        #create 'a' object
917
        self.upload_random_data('test', 'a')
918
        #look for 'a ' object
919
        self.assert_raises_fault(404, self.client.retrieve_object,
920
                                 'test', 'a ')
921

    
922
        #delete 'a' object
923
        self.client.delete_object('test', 'a')
924
        self.assert_raises_fault(404, self.client.retrieve_object,
925
                                 'test', 'a')
926

    
927
        #create 'a ' object
928
        self.upload_random_data('test', 'a ')
929
        #look for 'a' object
930
        self.assert_raises_fault(404, self.client.retrieve_object,
931
                                 'test', 'a')
932

    
933
    def test_get_invalid(self):
934
        self.assert_raises_fault(404, self.client.retrieve_object,
935
                                 self.containers[0], self.objects[0]['name'])
936

    
937
    def test_get_partial(self):
938
        #perform get with range
939
        status, headers, data = self.client.request_object(self.containers[1],
940
                                                            self.objects[0]['name'],
941
                                                            range='bytes=0-499')
942

    
943
        #assert successful partial content
944
        self.assertEqual(status, 206)
945

    
946
        #assert content-type
947
        self.assertEqual(headers['content-type'],
948
                         self.objects[0]['meta']['content_type'])
949

    
950
        #assert content length
951
        self.assertEqual(int(headers['content-length']), 500)
952

    
953
        #assert content
954
        self.assertEqual(self.objects[0]['data'][:500], data)
955

    
956
    def test_get_final_500(self):
957
        #perform get with range
958
        headers = {'range':'bytes=-500'}
959
        status, headers, data = self.client.request_object(self.containers[1],
960
                                                            self.objects[0]['name'],
961
                                                            range='bytes=-500')
962

    
963
        #assert successful partial content
964
        self.assertEqual(status, 206)
965

    
966
        #assert content-type
967
        self.assertEqual(headers['content-type'],
968
                         self.objects[0]['meta']['content_type'])
969

    
970
        #assert content length
971
        self.assertEqual(int(headers['content-length']), 500)
972

    
973
        #assert content
974
        self.assertTrue(self.objects[0]['data'][-500:], data)
975

    
976
    def test_get_rest(self):
977
        #perform get with range
978
        offset = len(self.objects[0]['data']) - 500
979
        status, headers, data = self.client.request_object(self.containers[1],
980
                                                self.objects[0]['name'],
981
                                                range='bytes=%s-' %offset)
982

    
983
        #assert successful partial content
984
        self.assertEqual(status, 206)
985

    
986
        #assert content-type
987
        self.assertEqual(headers['content-type'],
988
                         self.objects[0]['meta']['content_type'])
989

    
990
        #assert content length
991
        self.assertEqual(int(headers['content-length']), 500)
992

    
993
        #assert content
994
        self.assertTrue(self.objects[0]['data'][-500:], data)
995

    
996
    def test_get_range_not_satisfiable(self):
997
        #perform get with range
998
        offset = len(self.objects[0]['data']) + 1
999

    
1000
        #assert range not satisfiable
1001
        self.assert_raises_fault(416, self.client.retrieve_object,
1002
                                 self.containers[1], self.objects[0]['name'],
1003
                                 range='bytes=0-%s' %offset)
1004

    
1005
    def test_multiple_range(self):
1006
        #perform get with multiple range
1007
        ranges = ['0-499', '-500', '1000-']
1008
        bytes = 'bytes=%s' % ','.join(ranges)
1009
        status, headers, data = self.client.request_object(self.containers[1],
1010
                                                           self.objects[0]['name'],
1011
                                                           range=bytes)
1012

    
1013
        # assert partial content
1014
        self.assertEqual(status, 206)
1015

    
1016
        # assert Content-Type of the reply will be multipart/byteranges
1017
        self.assertTrue(headers['content-type'])
1018
        content_type_parts = headers['content-type'].split()
1019
        self.assertEqual(content_type_parts[0], ('multipart/byteranges;'))
1020

    
1021
        boundary = '--%s' %content_type_parts[1].split('=')[-1:][0]
1022
        cparts = data.split(boundary)[1:-1]
1023

    
1024
        # assert content parts are exactly 2
1025
        self.assertEqual(len(cparts), len(ranges))
1026

    
1027
        # for each content part assert headers
1028
        i = 0
1029
        for cpart in cparts:
1030
            content = cpart.split('\r\n')
1031
            headers = content[1:3]
1032
            content_range = headers[0].split(': ')
1033
            self.assertEqual(content_range[0], 'Content-Range')
1034

    
1035
            r = ranges[i].split('-')
1036
            if not r[0] and not r[1]:
1037
                pass
1038
            elif not r[0]:
1039
                start = len(self.objects[0]['data']) - int(r[1])
1040
                end = len(self.objects[0]['data'])
1041
            elif not r[1]:
1042
                start = int(r[0])
1043
                end = len(self.objects[0]['data'])
1044
            else:
1045
                start = int(r[0])
1046
                end = int(r[1]) + 1
1047
            fdata = self.objects[0]['data'][start:end]
1048
            sdata = '\r\n'.join(content[4:-1])
1049
            self.assertEqual(len(fdata), len(sdata))
1050
            self.assertEquals(fdata, sdata)
1051
            i+=1
1052

    
1053
    def test_multiple_range_not_satisfiable(self):
1054
        #perform get with multiple range
1055
        out_of_range = len(self.objects[0]['data']) + 1
1056
        ranges = ['0-499', '-500', '%d-' %out_of_range]
1057
        bytes = 'bytes=%s' % ','.join(ranges)
1058

    
1059
        # assert partial content
1060
        self.assert_raises_fault(416, self.client.retrieve_object,
1061
                                 self.containers[1],
1062
                                 self.objects[0]['name'], range=bytes)
1063

    
1064
    def test_get_with_if_match(self):
1065
        #perform get with If-Match
1066
        etag = self.objects[0]['hash']
1067
        status, headers, data = self.client.request_object(self.containers[1],
1068
                                                           self.objects[0]['name'],
1069
                                                           if_match=etag)
1070
        #assert get success
1071
        self.assertEqual(status, 200)
1072

    
1073
        #assert content-type
1074
        self.assertEqual(headers['content-type'],
1075
                         self.objects[0]['meta']['content_type'])
1076

    
1077
        #assert response content
1078
        self.assertEqual(self.objects[0]['data'], data)
1079

    
1080
    def test_get_with_if_match_star(self):
1081
        #perform get with If-Match *
1082
        headers = {'if-match':'*'}
1083
        status, headers, data = self.client.request_object(self.containers[1],
1084
                                                self.objects[0]['name'],
1085
                                                **headers)
1086
        #assert get success
1087
        self.assertEqual(status, 200)
1088

    
1089
        #assert content-type
1090
        self.assertEqual(headers['content-type'],
1091
                         self.objects[0]['meta']['content_type'])
1092

    
1093
        #assert response content
1094
        self.assertEqual(self.objects[0]['data'], data)
1095

    
1096
    def test_get_with_multiple_if_match(self):
1097
        #perform get with If-Match
1098
        etags = [i['hash'] for i in self.objects if i]
1099
        etags = ','.join('"%s"' % etag for etag in etags)
1100
        status, headers, data = self.client.request_object(self.containers[1],
1101
                                                           self.objects[0]['name'],
1102
                                                           if_match=etags)
1103
        #assert get success
1104
        self.assertEqual(status, 200)
1105

    
1106
        #assert content-type
1107
        self.assertEqual(headers['content-type'],
1108
                         self.objects[0]['meta']['content_type'])
1109

    
1110
        #assert content-type
1111
        self.assertEqual(headers['content-type'],
1112
                         self.objects[0]['meta']['content_type'])
1113

    
1114
        #assert response content
1115
        self.assertEqual(self.objects[0]['data'], data)
1116

    
1117
    def test_if_match_precondition_failed(self):
1118
        #assert precondition failed
1119
        self.assert_raises_fault(412, self.client.retrieve_object,
1120
                                 self.containers[1],
1121
                                 self.objects[0]['name'], if_match='123')
1122

    
1123
    def test_if_none_match(self):
1124
        #perform get with If-None-Match
1125
        status, headers, data = self.client.request_object(self.containers[1],
1126
                                                           self.objects[0]['name'],
1127
                                                           if_none_match='123')
1128

    
1129
        #assert get success
1130
        self.assertEqual(status, 200)
1131

    
1132
        #assert content-type
1133
        self.assertEqual(headers['content_type'],
1134
                         self.objects[0]['meta']['content_type'])
1135

    
1136
    def test_if_none_match(self):
1137
        #perform get with If-None-Match * and assert not modified
1138
        self.assert_raises_fault(304, self.client.retrieve_object,
1139
                                 self.containers[1],
1140
                                 self.objects[0]['name'],
1141
                                 if_none_match='*')
1142

    
1143
    def test_if_none_match_not_modified(self):
1144
        #perform get with If-None-Match and assert not modified
1145
        self.assert_raises_fault(304, self.client.retrieve_object,
1146
                                 self.containers[1],
1147
                                 self.objects[0]['name'],
1148
                                 if_none_match=self.objects[0]['hash'])
1149

    
1150
        meta = self.client.retrieve_object_metadata(self.containers[1],
1151
                                                    self.objects[0]['name'])
1152
        self.assertEqual(meta['etag'], self.objects[0]['hash'])
1153

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

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

    
1163
        for f in DATE_FORMATS:
1164
            past = t2.strftime(f)
1165

    
1166
            headers = {'if-modified-since':'%s' %past}
1167
            try:
1168
                o = self.client.retrieve_object(self.containers[1],
1169
                                                self.objects[0]['name'],
1170
                                                if_modified_since=past)
1171
                self.assertEqual(o,
1172
                                 self.client.retrieve_object(self.containers[1],
1173
                                                             self.objects[0]['name']))
1174
            except Fault, f:
1175
                self.failIf(f.status == 304)
1176

    
1177
    def test_if_modified_since_invalid_date(self):
1178
        o = self.client.retrieve_object(self.containers[1],
1179
                                        self.objects[0]['name'],
1180
                                        if_modified_since='')
1181
        self.assertEqual(o, self.client.retrieve_object(self.containers[1],
1182
                                                        self.objects[0]['name']))
1183

    
1184
    def test_if_not_modified_since(self):
1185
        now = datetime.datetime.utcnow()
1186
        since = now + datetime.timedelta(1)
1187

    
1188
        for f in DATE_FORMATS:
1189
            #assert not modified
1190
            self.assert_raises_fault(304, self.client.retrieve_object,
1191
                                     self.containers[1], self.objects[0]['name'],
1192
                                     if_modified_since=since.strftime(f))
1193

    
1194
    def test_if_unmodified_since(self):
1195
        now = datetime.datetime.utcnow()
1196
        since = now + datetime.timedelta(1)
1197

    
1198
        for f in DATE_FORMATS:
1199
            t = since.strftime(f)
1200
            status, headers, data = self.client.request_object(self.containers[1],
1201
                                                               self.objects[0]['name'],
1202
                                                               if_unmodified_since=t)
1203
            #assert success
1204
            self.assertEqual(status, 200)
1205
            self.assertEqual(self.objects[0]['data'], data)
1206

    
1207
            #assert content-type
1208
            self.assertEqual(headers['content-type'],
1209
                             self.objects[0]['meta']['content_type'])
1210

    
1211
    def test_if_unmodified_since_precondition_failed(self):
1212
        t = datetime.datetime.utcnow()
1213
        t2 = t - datetime.timedelta(minutes=10)
1214

    
1215
        #modify the object
1216
        self.upload_data(self.containers[1],
1217
                           self.objects[0]['name'],
1218
                           self.objects[0]['data'][:200])
1219

    
1220
        for f in DATE_FORMATS:
1221
            past = t2.strftime(f)
1222
            #assert precondition failed
1223
            self.assert_raises_fault(412, self.client.retrieve_object,
1224
                                     self.containers[1], self.objects[0]['name'],
1225
                                     if_unmodified_since=past)
1226

    
1227
    def test_hashes(self):
1228
        l = 8388609
1229
        fname = 'largefile'
1230
        o = self.upload_random_data(self.containers[1], fname, l)
1231
        if o:
1232
            body = self.client.retrieve_object(self.containers[1], fname,
1233
                                               format='json')
1234
            hashes = body['hashes']
1235
            block_size = body['block_size']
1236
            block_hash = body['block_hash']
1237
            block_num = l/block_size if l/block_size == 0 else l/block_size + 1
1238
            self.assertTrue(len(hashes), block_num)
1239
            i = 0
1240
            for h in hashes:
1241
                start = i * block_size
1242
                end = (i + 1) * block_size
1243
                hash = compute_block_hash(o['data'][start:end], block_hash)
1244
                self.assertEqual(h, hash)
1245
                i += 1
1246

    
1247
class ObjectPut(BaseTestCase):
1248
    def setUp(self):
1249
        BaseTestCase.setUp(self)
1250
        self.container = 'c1'
1251
        self.client.create_container(self.container)
1252

    
1253
    def test_upload(self):
1254
        name = o_names[0]
1255
        meta = {'test':'test1'}
1256
        o = self.upload_random_data(self.container, name, **meta)
1257

    
1258
        headers = self.client.retrieve_object_metadata(self.container,
1259
                                                       name,
1260
                                                       restricted=True)
1261
        self.assertTrue('test' in headers.keys())
1262
        self.assertEqual(headers['test'], meta['test'])
1263

    
1264
        #assert uploaded content
1265
        status, h, data = self.client.request_object(self.container, name)
1266
        self.assertEqual(len(o['data']), int(h['content-length']))
1267
        self.assertEqual(o['data'], data)
1268

    
1269
        #assert content-type
1270
        self.assertEqual(h['content-type'], o['meta']['content_type'])
1271

    
1272
    def _test_maximum_upload_size_exceeds(self):
1273
        name = o_names[0]
1274
        meta = {'test':'test1'}
1275
        #upload 5GB
1276
        length= 5 * (1024 * 1024 * 1024) + 1
1277
        self.assert_raises_fault(400, self.upload_random_data, self.container,
1278
                                 name, length, **meta)
1279

    
1280
    def test_upload_with_name_containing_slash(self):
1281
        name = '/%s' % o_names[0]
1282
        meta = {'test':'test1'}
1283
        o = self.upload_random_data(self.container, name, **meta)
1284

    
1285
        self.assertEqual(o['data'],
1286
                         self.client.retrieve_object(self.container, name))
1287

    
1288
        self.assertTrue(name in self.client.list_objects(self.container))
1289

    
1290
    def test_create_directory_marker(self):
1291
        self.client.create_directory_marker(self.container, 'foo')
1292
        meta = self.client.retrieve_object_metadata(self.container, 'foo')
1293
        self.assertEqual(meta['content-length'], '0')
1294
        self.assertEqual(meta['content-type'], 'application/directory')
1295

    
1296
    def test_upload_unprocessable_entity(self):
1297
        meta={'etag':'123', 'test':'test1'}
1298

    
1299
        #assert unprocessable entity
1300
        self.assert_raises_fault(422, self.upload_random_data, self.container,
1301
                                 o_names[0], **meta)
1302

    
1303
    def test_chunked_transfer(self):
1304
        data = get_random_data()
1305
        objname = 'object'
1306
        self.client.create_object_using_chunks(self.container, objname,
1307
                                               StringIO(data))
1308

    
1309
        uploaded_data = self.client.retrieve_object(self.container, objname)
1310
        self.assertEqual(data, uploaded_data)
1311

    
1312
    def test_manifestation(self):
1313
        prefix = 'myobject/'
1314
        data = ''
1315
        for i in range(5):
1316
            part = '%s%d' %(prefix, i)
1317
            o = self.upload_random_data(self.container, part)
1318
            data += o['data']
1319

    
1320
        manifest = '%s/%s' %(self.container, prefix)
1321
        self.client.create_manifestation(self.container, 'large-object', manifest)
1322

    
1323
        self.assert_object_exists(self.container, 'large-object')
1324
        self.assertEqual(data, self.client.retrieve_object(self.container,
1325
                                                           'large-object'))
1326
        
1327
        r = self.client.retrieve_object_hashmap(self.container,'large-object')
1328
        hashes = r['hashes']
1329
        block_size = int(r['block_size'])
1330
        block_hash = r['block_hash']
1331
        l = len(data)
1332
        block_num = l/block_size if l/block_size != 0 else l/block_size + 1
1333
        self.assertEqual(block_num, len(hashes))
1334
        
1335
        #wrong manifestation
1336
        self.client.create_manifestation(self.container, 'large-object',
1337
                                         '%s/invalid' % self.container)
1338
        self.assertEqual('', self.client.retrieve_object(self.container,
1339
                                                         'large-object'))
1340

    
1341
    def test_create_zero_length_object(self):
1342
        c = self.container
1343
        o = 'object'
1344
        zero = self.client.create_zero_length_object(c, o)
1345
        zero_meta = self.client.retrieve_object_metadata(c, o)
1346
        zero_hash = self.client.retrieve_object_hashmap(c, o)["hashes"]
1347
        zero_data = self.client.retrieve_object(c, o)
1348

    
1349
        self.assertEqual(int(zero_meta['content-length']), 0)
1350
        hasher = newhasher('sha256')
1351
        hasher.update("")
1352
        emptyhash = hasher.digest()
1353
        self.assertEqual(zero_hash, [hexlify(emptyhash)])
1354
        self.assertEqual(zero_data, '')
1355

    
1356
    def test_create_object_by_hashmap(self):
1357
        c = self.container
1358
        o = 'object'
1359
        self.upload_random_data(c, o)
1360
        hashmap = self.client.retrieve_object(c, o, format='json')
1361
        o2 = 'object-copy'
1362
        self.client.create_object_by_hashmap(c, o2, hashmap)
1363
        self.assertEqual(self.client.retrieve_object(c, o),
1364
                         self.client.retrieve_object(c, o))
1365

    
1366
class ObjectCopy(BaseTestCase):
1367
    def setUp(self):
1368
        BaseTestCase.setUp(self)
1369
        self.containers = ['c1', 'c2']
1370
        for c in self.containers:
1371
            self.client.create_container(c)
1372
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1373

    
1374
    def test_copy(self):
1375
        with AssertMappingInvariant(self.client.retrieve_object_metadata,
1376
                             self.containers[0], self.obj['name']):
1377
            #perform copy
1378
            meta = {'test':'testcopy'}
1379
            status = self.client.copy_object(self.containers[0],
1380
                                              self.obj['name'],
1381
                                              self.containers[0],
1382
                                              'testcopy',
1383
                                              meta)[0]
1384

    
1385
            #assert copy success
1386
            self.assertEqual(status, 201)
1387

    
1388
            #assert access the new object
1389
            headers = self.client.retrieve_object_metadata(self.containers[0],
1390
                                                           'testcopy')
1391
            self.assertTrue('x-object-meta-test' in headers.keys())
1392
            self.assertTrue(headers['x-object-meta-test'], 'testcopy')
1393

    
1394
            #assert etag is the same
1395
            self.assertEqual(headers['etag'], self.obj['hash'])
1396

    
1397
            #assert src object still exists
1398
            self.assert_object_exists(self.containers[0], self.obj['name'])
1399

    
1400
    def test_copy_from_different_container(self):
1401
        with AssertMappingInvariant(self.client.retrieve_object_metadata,
1402
                             self.containers[0], self.obj['name']):
1403
            meta = {'test':'testcopy'}
1404
            status = self.client.copy_object(self.containers[0],
1405
                                             self.obj['name'],
1406
                                             self.containers[1],
1407
                                             'testcopy',
1408
                                             meta)[0]
1409
            self.assertEqual(status, 201)
1410

    
1411
            # assert updated metadata
1412
            meta = self.client.retrieve_object_metadata(self.containers[1],
1413
                                                           'testcopy',
1414
                                                           restricted=True)
1415
            self.assertTrue('test' in meta.keys())
1416
            self.assertTrue(meta['test'], 'testcopy')
1417

    
1418
            #assert src object still exists
1419
            self.assert_object_exists(self.containers[0], self.obj['name'])
1420

    
1421
    def test_copy_invalid(self):
1422
        #copy from invalid object
1423
        meta = {'test':'testcopy'}
1424
        self.assert_raises_fault(404, self.client.copy_object, self.containers[0],
1425
                                 'test.py', self.containers[1], 'testcopy', meta)
1426

    
1427
        #copy from invalid container
1428
        meta = {'test':'testcopy'}
1429
        self.assert_raises_fault(404, self.client.copy_object, self.containers[1],
1430
                                 self.obj['name'], self.containers[1],
1431
                                 'testcopy', meta)
1432
    
1433
    def test_copy_dir(self):
1434
        self.client.create_folder(self.containers[0], 'dir')
1435
        objects = ('object1.jpg', 'subdir/object2.pdf', 'dirs')
1436
        for name, i in zip(objects[:-1], range(1, len(objects[:-1])+1)):
1437
            self.upload_random_data(self.containers[0], 'dir/%s' % name, length=i*1024)
1438
        self.upload_random_data(self.containers[0], 'dirs')
1439
        
1440
        self.client.copy_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/')
1441
        self.assert_object_exists(self.containers[0], 'dir')
1442
        self.assert_object_not_exists(self.containers[1], 'dirs')
1443
        for name in objects[:-1]:
1444
            meta0 = self.client.retrieve_object_metadata(self.containers[0], 'dir/%s' % name)
1445
            meta1 = self.client.retrieve_object_metadata(self.containers[1], 'dir-backup/%s' % name)
1446
            t = ('content-length', 'x-object-hash', 'content-type')
1447
            (self.assertEqual(meta0[elem], meta1[elem]) for elem in t)
1448
        
1449
class ObjectMove(BaseTestCase):
1450
    def setUp(self):
1451
        BaseTestCase.setUp(self)
1452
        self.containers = ['c1', 'c2']
1453
        for c in self.containers:
1454
            self.client.create_container(c)
1455
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1456

    
1457
    def test_move(self):
1458
        meta = self.client.retrieve_object_metadata(self.containers[0],
1459
                                                    self.obj['name'])
1460
        self.assertTrue('x-object-uuid' in meta)
1461
        uuid = meta['x-object-uuid']
1462

    
1463
        #perform move
1464
        meta = {'test':'testcopy'}
1465
        src_path = '/'.join(('/', self.containers[0], self.obj['name']))
1466
        status = self.client.move_object(self.containers[0], self.obj['name'],
1467
                                         self.containers[0], 'testcopy',
1468
                                         meta)[0]
1469

    
1470
        #assert successful move
1471
        self.assertEqual(status, 201)
1472

    
1473
        #assert updated metadata
1474
        meta = self.client.retrieve_object_metadata(self.containers[0],
1475
                                                    'testcopy')
1476
        self.assertTrue('x-object-meta-test' in meta.keys())
1477
        self.assertTrue(meta['x-object-meta-test'], 'testcopy')
1478

    
1479
        #assert same uuid
1480
        self.assertTrue(meta['x-object-uuid'], uuid)
1481

    
1482
        #assert src object no more exists
1483
        self.assert_object_not_exists(self.containers[0], self.obj['name'])
1484
    
1485
    
1486
    def test_move_dir(self):
1487
        self.client.create_folder(self.containers[0], 'dir')
1488
        objects = ('object1.jpg', 'subdir/object2.pdf', 'dirs')
1489
        meta = {}
1490
        for name, i in zip(objects[:-1], range(1, len(objects[:-1])+1)):
1491
            self.upload_random_data(self.containers[0], 'dir/%s' % name, length=i*1024)
1492
            meta[name] = self.client.retrieve_object_metadata(self.containers[0], 'dir/%s' % name)
1493
        self.upload_random_data(self.containers[0], 'dirs')
1494
        
1495
        self.client.move_object(self.containers[0], 'dir', self.containers[1], 'dir-backup', delimiter='/', content_type='application/folder')
1496
        self.assert_object_not_exists(self.containers[0], 'dir')
1497
        self.assert_object_not_exists(self.containers[1], 'dirs')
1498
        for name in objects[:-1]:
1499
            self.assert_object_not_exists(self.containers[0], 'dir/%s' % name)
1500
            self.assert_object_exists(self.containers[1], 'dir-backup/%s' % name)
1501
            meta1 = self.client.retrieve_object_metadata(self.containers[1], 'dir-backup/%s' % name)
1502
            t = ('content-length', 'x-object-hash', 'content-type')
1503
            (self.assertEqual(meta[name][elem], meta1[elem]) for elem in t)
1504

    
1505
class ObjectPost(BaseTestCase):
1506
    def setUp(self):
1507
        BaseTestCase.setUp(self)
1508
        self.containers = ['c1', 'c2']
1509
        for c in self.containers:
1510
            self.client.create_container(c)
1511
        self.obj = []
1512
        for i in range(2):
1513
            self.obj.append(self.upload_random_data(self.containers[0], o_names[i]))
1514

    
1515
    def test_update_meta(self):
1516
        with AssertUUidInvariant(self.client.retrieve_object_metadata,
1517
                                 self.containers[0],
1518
                                 self.obj[0]['name']):
1519
            #perform update metadata
1520
            more = {'foo': 'foo', 'bar': 'bar', 'f' * 114: 'b' * 256}
1521
            status = self.client.update_object_metadata(self.containers[0],
1522
                                                        self.obj[0]['name'],
1523
                                                        **more)[0]
1524
            #assert request accepted
1525
            self.assertEqual(status, 202)
1526

    
1527
            #assert old metadata are still there
1528
            headers = self.client.retrieve_object_metadata(self.containers[0],
1529
                                                           self.obj[0]['name'],
1530
                                                           restricted=True)
1531
            #assert new metadata have been updated
1532
            for k,v in more.items():
1533
                self.assertTrue(k in headers.keys())
1534
                self.assertTrue(headers[k], v)
1535

    
1536
            #out of limits
1537
            more = {'f' * 114: 'b' * 257}
1538
            self.assert_raises_fault(400, self.client.update_object_metadata,
1539
                                                        self.containers[0],
1540
                                                        self.obj[0]['name'],
1541
                                                        **more)
1542
            
1543
            #perform update metadata
1544
            more = {'α': 'β' * 256}
1545
            status = self.client.update_object_metadata(self.containers[0],
1546
                                                        self.obj[0]['name'],
1547
                                                        **more)[0]
1548
            #assert request accepted
1549
            self.assertEqual(status, 202)
1550
            
1551
            #assert old metadata are still there
1552
            headers = self.client.retrieve_object_metadata(self.containers[0],
1553
                                                           self.obj[0]['name'],
1554
                                                           restricted=True)
1555
            #assert new metadata have been updated
1556
            for k,v in more.items():
1557
                self.assertTrue(k in headers.keys())
1558
                self.assertTrue(headers[k], v)
1559
            
1560
            #out of limits
1561
            more = {'α': 'β' * 257}
1562
            self.assert_raises_fault(400, self.client.update_object_metadata,
1563
                                                        self.containers[0],
1564
                                                        self.obj[0]['name'],
1565
                                                        **more)
1566
    
1567
    def test_update_object(self,
1568
                           first_byte_pos=0,
1569
                           last_byte_pos=499,
1570
                           instance_length = True,
1571
                           content_length = 500):
1572
        with AssertUUidInvariant(self.client.retrieve_object_metadata,
1573
                                 self.containers[0],
1574
                                 self.obj[0]['name']):
1575
            l = len(self.obj[0]['data'])
1576
            range = 'bytes %d-%d/%s' %(first_byte_pos,
1577
                                           last_byte_pos,
1578
                                            l if instance_length else '*')
1579
            partial = last_byte_pos - first_byte_pos + 1
1580
            length = first_byte_pos + partial
1581
            data = get_random_data(partial)
1582
            args = {'content_type':'application/octet-stream',
1583
                    'content_range':'%s' %range}
1584
            if content_length:
1585
                args['content_length'] = content_length
1586

    
1587
            r = self.client.update_object(self.containers[0], self.obj[0]['name'],
1588
                                      StringIO(data), **args)
1589
            status = r[0]
1590
            etag = r[1]['etag']
1591
            if partial < 0 or (instance_length and l <= last_byte_pos):
1592
                self.assertEqual(status, 202)
1593
            else:
1594
                self.assertEqual(status, 204)
1595
                #check modified object
1596
                content = self.client.retrieve_object(self.containers[0],
1597
                                                  self.obj[0]['name'])
1598
                self.assertEqual(content[:first_byte_pos], self.obj[0]['data'][:first_byte_pos])
1599
                self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1600
                self.assertEqual(content[last_byte_pos+1:], self.obj[0]['data'][last_byte_pos+1:])
1601
                self.assertEqual(etag, compute_md5_hash(content))
1602

    
1603
    def test_update_object_lt_blocksize(self):
1604
        self.test_update_object(10, 20, content_length=None)
1605

    
1606
    def test_update_object_gt_blocksize(self):
1607
        o = self.upload_random_data(self.containers[0], o_names[1],
1608
                                length=4*1024*1024+5)
1609
        c = self.containers[0]
1610
        o_name = o['name']
1611
        o_data = o['data']
1612
        first_byte_pos = 4*1024*1024+1
1613
        last_byte_pos = 4*1024*1024+4
1614
        l = last_byte_pos - first_byte_pos + 1
1615
        data = get_random_data(l)
1616
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1617
        self.client.update_object(c, o_name, StringIO(data), content_range=range)
1618
        content = self.client.retrieve_object(c, o_name)
1619
        self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1620
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1621
        self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1622

    
1623
    def test_update_object_divided_by_blocksize(self):
1624
        o = self.upload_random_data(self.containers[0], o_names[1],
1625
                                length=4*1024*1024+5)
1626
        c = self.containers[0]
1627
        o_name = o['name']
1628
        o_data = o['data']
1629
        first_byte_pos = 4*1024*1024
1630
        last_byte_pos = 5*1024*1024
1631
        l = last_byte_pos - first_byte_pos + 1
1632
        data = get_random_data(l)
1633
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1634
        self.client.update_object(c, o_name, StringIO(data), content_range=range)
1635
        content = self.client.retrieve_object(c, o_name)
1636
        self.assertEqual(content[:first_byte_pos], o_data[:first_byte_pos])
1637
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], data)
1638
        self.assertEqual(content[last_byte_pos+1:], o_data[last_byte_pos+1:])
1639

    
1640
    def test_update_object_no_content_length(self):
1641
        self.test_update_object(content_length = None)
1642

    
1643
    def test_update_object_invalid_content_length(self):
1644
        with AssertContentInvariant(self.client.retrieve_object,
1645
                                    self.containers[0], self.obj[0]['name']):
1646
            self.assert_raises_fault(400, self.test_update_object,
1647
                                     content_length = 1000)
1648

    
1649
    def test_update_object_invalid_range(self):
1650
        with AssertContentInvariant(self.client.retrieve_object,
1651
                                    self.containers[0], self.obj[0]['name']):
1652
            self.assert_raises_fault(416, self.test_update_object, 499, 0, True)
1653

    
1654
    def test_update_object_invalid_range_and_length(self):
1655
        with AssertContentInvariant(self.client.retrieve_object,
1656
                                    self.containers[0], self.obj[0]['name']):
1657
            self.assert_raises_fault([400, 416], self.test_update_object, 499, 0, True,
1658
                                     -1)
1659

    
1660
    def test_update_object_invalid_range_with_no_content_length(self):
1661
        with AssertContentInvariant(self.client.retrieve_object,
1662
                                    self.containers[0], self.obj[0]['name']):
1663
            self.assert_raises_fault(416, self.test_update_object, 499, 0, True,
1664
                                     content_length = None)
1665

    
1666
    def test_update_object_out_of_limits(self):
1667
        with AssertContentInvariant(self.client.retrieve_object,
1668
                                    self.containers[0], self.obj[0]['name']):
1669
            l = len(self.obj[0]['data'])
1670
            self.assert_raises_fault(416, self.test_update_object, 0, l+1, True)
1671

    
1672
    def test_append(self):
1673
        data = get_random_data(500)
1674
        headers = {}
1675
        self.client.update_object(self.containers[0], self.obj[0]['name'],
1676
                                  StringIO(data), content_length=500,
1677
                                  content_type='application/octet-stream')
1678

    
1679
        content = self.client.retrieve_object(self.containers[0],
1680
                                              self.obj[0]['name'])
1681
        self.assertEqual(len(content), len(self.obj[0]['data']) + 500)
1682
        self.assertEqual(content[:-500], self.obj[0]['data'])
1683

    
1684
    def test_update_with_chunked_transfer(self):
1685
        data = get_random_data(500)
1686
        dl = len(data)
1687
        fl = len(self.obj[0]['data'])
1688

    
1689
        self.client.update_object_using_chunks(self.containers[0],
1690
                                               self.obj[0]['name'],
1691
                                               StringIO(data),
1692
                                               offset=0,
1693
                                               content_type='application/octet-stream')
1694

    
1695
        #check modified object
1696
        content = self.client.retrieve_object(self.containers[0],
1697
                                              self.obj[0]['name'])
1698
        self.assertEqual(content[0:dl], data)
1699
        self.assertEqual(content[dl:fl], self.obj[0]['data'][dl:fl])
1700

    
1701
    def test_update_from_other_object(self):
1702
        c = self.containers[0]
1703
        src = o_names[0]
1704
        dest = 'object'
1705

    
1706
        source_data = self.client.retrieve_object(c, src)
1707
        source_meta = self.client.retrieve_object_metadata(c, src)
1708
        source_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1709

    
1710
        #update zero length object
1711
        self.client.create_zero_length_object(c, dest)
1712
        source_object = '/%s/%s' % (c, src)
1713
        self.client.update_from_other_source(c, dest, source_object)
1714
        dest_data = self.client.retrieve_object(c, src)
1715
        dest_meta = self.client.retrieve_object_metadata(c, dest)
1716
        dest_hash = self.client.retrieve_object_hashmap(c, src)["hashes"]
1717
        self.assertEqual(source_data, dest_data)
1718
        self.assertEqual(source_hash, dest_hash)
1719

    
1720
        #test append
1721
        self.client.update_from_other_source(c, dest, source_object)
1722
        content = self.client.retrieve_object(c, dest)
1723
        self.assertEqual(source_data * 2, content)
1724

    
1725
    def test_update_range_from_other_object(self):
1726
        c = self.containers[0]
1727
        dest = 'object'
1728

    
1729
        #test update range
1730
        src = self.obj[1]['name']
1731
        src_data = self.client.retrieve_object(c, src)
1732

    
1733
        #update zero length object
1734
        prev_data = self.upload_random_data(c, dest, length=4*1024*1024+10)['data']
1735
        source_object = '/%s/%s' % (c, src)
1736
        first_byte_pos = 4*1024*1024+1
1737
        last_byte_pos = 4*1024*1024+4
1738
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1739
        self.client.update_from_other_source(c, dest, source_object,
1740
                                             content_range=range)
1741
        content = self.client.retrieve_object(c, dest)
1742
        self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1743
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1744
        self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1745

    
1746
    def test_update_hashes_from_other_object(self):
1747
        c = self.containers[0]
1748
        dest = 'object'
1749

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

    
1753
        #update zero length object
1754
        prev_data = self.upload_random_data(c, dest, length=5*1024*1024+10)['data']
1755
        source_object = '/%s/%s' % (c, o_names[0])
1756
        first_byte_pos = 4*1024*1024
1757
        last_byte_pos = 5*1024*1024
1758
        range = 'bytes %d-%d/*' %(first_byte_pos, last_byte_pos)
1759
        self.client.update_from_other_source(c, dest, source_object,
1760
                                             content_range=range)
1761
        content = self.client.retrieve_object(c, dest)
1762
        self.assertEqual(content[:first_byte_pos], prev_data[:first_byte_pos])
1763
        self.assertEqual(content[first_byte_pos:last_byte_pos+1], src_data[:last_byte_pos - first_byte_pos + 1])
1764
        self.assertEqual(content[last_byte_pos+1:], prev_data[last_byte_pos+1:])
1765

    
1766

    
1767
    def test_update_zero_length_object(self):
1768
        c = self.containers[0]
1769
        o = 'object'
1770
        other = 'other'
1771
        zero = self.client.create_zero_length_object(c, o)
1772

    
1773
        data = get_random_data()
1774
        self.client.update_object(c, o, StringIO(data))
1775
        self.client.create_object(c, other, StringIO(data))
1776

    
1777
        self.assertEqual(self.client.retrieve_object(c, o),
1778
                         self.client.retrieve_object(c, other))
1779

    
1780
        self.assertEqual(self.client.retrieve_object_hashmap(c, o)["hashes"],
1781
                         self.client.retrieve_object_hashmap(c, other)["hashes"])
1782

    
1783
class ObjectDelete(BaseTestCase):
1784
    def setUp(self):
1785
        BaseTestCase.setUp(self)
1786
        self.containers = ['c1', 'c2']
1787
        for c in self.containers:
1788
            self.client.create_container(c)
1789
        self.obj = self.upload_random_data(self.containers[0], o_names[0])
1790

    
1791
    def test_delete(self):
1792
        #perform delete object
1793
        self.client.delete_object(self.containers[0], self.obj['name'])[0]
1794

    
1795
    def test_delete_invalid(self):
1796
        #assert item not found
1797
        self.assert_raises_fault(404, self.client.delete_object, self.containers[1],
1798
                                 self.obj['name'])
1799
    
1800
    def test_delete_dir(self):
1801
        self.client.create_folder(self.containers[0], 'dir')
1802
        objects = ('object1.jpg', 'subdir/object2.pdf', 'dirs')
1803
        for name in objects[:-1]:
1804
            self.upload_random_data(self.containers[0], 'dir/%s' % name)
1805
        self.upload_random_data(self.containers[0], 'dirs')
1806
        
1807
        self.client.delete_object(self.containers[0], 'dir', delimiter='/')
1808
        self.assert_object_not_exists(self.containers[0], 'dir')
1809
        self.assert_object_exists(self.containers[0], 'dirs')
1810
        for name in objects[:-1]:
1811
            self.assert_object_not_exists(self.containers[0], 'dir/%s' % name)
1812

    
1813
class ListSharing(BaseTestCase):
1814
    def setUp(self):
1815
        BaseTestCase.setUp(self)
1816
        for i in range(2):
1817
            self.client.create_container('c%s' %i)
1818
        self.client.create_container('c')
1819
        for i in range(2):
1820
            self.upload_random_data('c1', 'o%s' %i)
1821
        accounts = OTHER_ACCOUNTS.copy()
1822
        self.o1_sharing_with = accounts.popitem()
1823
        self.o1_sharing = [self.o1_sharing_with[1]]
1824
        self.client.share_object('c1', 'o1', self.o1_sharing, read=True)
1825

    
1826
        l = []
1827
        for i in range(2):
1828
            l.append(accounts.popitem())
1829

    
1830
    def test_list_other_shared(self):
1831
        self.other = Pithos_Client(get_url(),
1832
                              self.o1_sharing_with[0],
1833
                              self.o1_sharing_with[1])
1834
        self.assertTrue(get_user() in self.other.list_shared_by_others())
1835

    
1836
    def test_list_my_shared(self):
1837
        my_shared_containers = self.client.list_containers(shared=True)
1838
        self.assertTrue('c1' in my_shared_containers)
1839
        self.assertTrue('c2' not in my_shared_containers)
1840

    
1841
        my_shared_objects = self.client.list_objects('c1', shared=True)
1842
        self.assertTrue('o1' in my_shared_objects)
1843
        self.assertTrue('o2' not in my_shared_objects)
1844

    
1845
class List(BaseTestCase):
1846
    def setUp(self):
1847
        BaseTestCase.setUp(self)
1848
        for i in range(1, 5):
1849
            c = 'c%s' % i
1850
            self.client.create_container(c)
1851
            for j in range(1, 3):
1852
                o = 'o%s' % j
1853
                self.upload_random_data(c, o)
1854
            if i < 3:
1855
                self.client.share_object(c, 'o1', ['papagian'], read=True)
1856
            if i%2 != 0:
1857
                self.client.publish_object(c, 'o2')
1858
    
1859
    def test_shared_public(self):
1860
        func, kwargs = self.client.list_containers, {'shared':True}
1861
        l = func(**kwargs)
1862
        self.assertEqual(l, ['c1', 'c2'])
1863
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1864
        
1865
        func, kwargs = self.client.list_containers, {'public':True}
1866
        l = func(**kwargs)
1867
        self.assertEqual(l, ['c1', 'c3'])
1868
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1869
        
1870
        func, kwargs = self.client.list_containers, {'shared':True, 'public':True}
1871
        l = func(**kwargs)
1872
        self.assertEqual(l, ['c1', 'c2', 'c3'])
1873
        self.assertEqual(l, [e['name'] for e in func(format='json', **kwargs)])
1874
        
1875
        
1876
        func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True}
1877
        l = func(*args, **kwargs)
1878
        self.assertEqual(l, ['o1'])
1879
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1880
        
1881
        func, args, kwargs = self.client.list_objects, ['c1'], {'public':True}
1882
        l = func(*args, **kwargs)
1883
        self.assertEqual(l, ['o2'])
1884
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1885
        
1886
        func, args, kwargs = self.client.list_objects, ['c1'], {'shared':True, 'public':True}
1887
        l = func(*args, **kwargs)
1888
        self.assertEqual(l, ['o1', 'o2'])
1889
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1890
        
1891
        
1892
        func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True}
1893
        l = func(*args, **kwargs)
1894
        self.assertEqual(l, ['o1'])
1895
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1896
        
1897
        func, args, kwargs = self.client.list_objects, ['c2'], {'public':True}
1898
        l = func(*args, **kwargs)
1899
        self.assertEqual(l, '')
1900
        self.assertEqual([], func(*args, format='json', **kwargs))
1901
        
1902
        func, args, kwargs = self.client.list_objects, ['c2'], {'shared':True, 'public':True}
1903
        l = func(*args, **kwargs)
1904
        self.assertEqual(l, ['o1'])
1905
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1906
        
1907
        
1908
        func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True}
1909
        l = func(*args, **kwargs)
1910
        self.assertEqual(l, '')
1911
        self.assertEqual([], func(*args, format='json', **kwargs))
1912
        
1913
        func, args, kwargs = self.client.list_objects, ['c3'], {'public':True}
1914
        l = func(*args, **kwargs)
1915
        self.assertEqual(l, ['o2'])
1916
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1917
        
1918
        func, args, kwargs = self.client.list_objects, ['c3'], {'shared':True, 'public':True}
1919
        l = func(*args, **kwargs)
1920
        self.assertEqual(l, ['o2'])
1921
        self.assertEqual(l, [e['name'] for e in func(*args, format='json', **kwargs)])
1922
        
1923
        
1924
        func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True}
1925
        l = func(*args, **kwargs)
1926
        self.assertEqual(l, '')
1927
        self.assertEqual([], func(*args, format='json', **kwargs))
1928
        
1929
        func, args, kwargs = self.client.list_objects, ['c4'], {'public':True}
1930
        l = func(*args, **kwargs)
1931
        self.assertEqual(l, '')
1932
        self.assertEqual([], func(*args, format='json', **kwargs))
1933
        
1934
        func, args, kwargs = self.client.list_objects, ['c4'], {'shared':True, 'public':True}
1935
        l = func(*args, **kwargs)
1936
        self.assertEqual(l, '')
1937
        self.assertEqual([], func(*args, format='json', **kwargs))
1938

    
1939
class TestGreek(BaseTestCase):
1940
    def test_create_container(self):
1941
        self.client.create_container('φάκελος')
1942
        self.assert_container_exists('φάκελος')
1943

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

    
1946
    def test_create_object(self):
1947
        self.client.create_container('φάκελος')
1948
        self.upload_random_data('φάκελος', 'αντικείμενο')
1949

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

    
1953
    def test_copy_object(self):
1954
        src_container = 'φάκελος'
1955
        src_object = 'αντικείμενο'
1956
        dest_container = 'αντίγραφα'
1957
        dest_object = 'ασφαλές-αντίγραφο'
1958

    
1959
        self.client.create_container(src_container)
1960
        self.upload_random_data(src_container, src_object)
1961

    
1962
        self.client.create_container(dest_container)
1963
        self.client.copy_object(src_container, src_object, dest_container,
1964
                                dest_object)
1965

    
1966
        self.assert_object_exists(src_container, src_object)
1967
        self.assert_object_exists(dest_container, dest_object)
1968
        self.assertTrue(dest_object in self.client.list_objects(dest_container))
1969

    
1970
    def test_move_object(self):
1971
        src_container = 'φάκελος'
1972
        src_object = 'αντικείμενο'
1973
        dest_container = 'αντίγραφα'
1974
        dest_object = 'ασφαλές-αντίγραφο'
1975

    
1976
        self.client.create_container(src_container)
1977
        self.upload_random_data(src_container, src_object)
1978

    
1979
        self.client.create_container(dest_container)
1980
        self.client.move_object(src_container, src_object, dest_container,
1981
                                dest_object)
1982

    
1983
        self.assert_object_not_exists(src_container, src_object)
1984
        self.assert_object_exists(dest_container, dest_object)
1985
        self.assertTrue(dest_object in self.client.list_objects(dest_container))
1986

    
1987
    def test_delete_object(self):
1988
        self.client.create_container('φάκελος')
1989
        self.upload_random_data('φάκελος', 'αντικείμενο')
1990
        self.assert_object_exists('φάκελος', 'αντικείμενο')
1991

    
1992
        self.client.delete_object('φάκελος', 'αντικείμενο')
1993
        self.assert_object_not_exists('φάκελος', 'αντικείμενο')
1994
        self.assertTrue('αντικείμενο' not in self.client.list_objects('φάκελος'))
1995

    
1996
    def test_delete_container(self):
1997
        self.client.create_container('φάκελος')
1998
        self.assert_container_exists('φάκελος')
1999

    
2000
        self.client.delete_container('φάκελος')
2001
        self.assert_container_not_exists('φάκελος')
2002
        self.assertTrue('φάκελος' not in self.client.list_containers())
2003

    
2004
    def test_account_meta(self):
2005
        meta = {'ποιότητα':'ΑΑΑ'}
2006
        self.client.update_account_metadata(**meta)
2007
        meta = self.client.retrieve_account_metadata(restricted=True)
2008
        self.assertTrue('ποιότητα' in meta.keys())
2009
        self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2010

    
2011
    def test_container_meta(self):
2012
        meta = {'ποιότητα':'ΑΑΑ'}
2013
        self.client.create_container('φάκελος', meta=meta)
2014

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

    
2019
    def test_object_meta(self):
2020
        self.client.create_container('φάκελος')
2021
        meta = {'ποιότητα':'ΑΑΑ'}
2022
        self.upload_random_data('φάκελος', 'αντικείμενο', **meta)
2023

    
2024
        meta = self.client.retrieve_object_metadata('φάκελος', 'αντικείμενο',
2025
                                                    restricted=True)
2026
        self.assertTrue('ποιότητα' in meta.keys())
2027
        self.assertEqual(meta['ποιότητα'], 'ΑΑΑ')
2028

    
2029
    def test_list_meta_filtering(self):
2030
        self.client.create_container('φάκελος')
2031
        meta = {'ποιότητα':'ΑΑΑ'}
2032
        self.upload_random_data('φάκελος', 'ο1', **meta)
2033
        self.upload_random_data('φάκελος', 'ο2')
2034
        self.upload_random_data('φάκελος', 'ο3')
2035

    
2036
        meta = {'ποσότητα':'μεγάλη'}
2037
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2038
        objects = self.client.list_objects('φάκελος', meta='ποιότητα, ποσότητα')
2039
        self.assertEquals(objects, ['ο1', 'ο2'])
2040

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

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

    
2047
        meta = {'ποιότητα':'ΑΒ'}
2048
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2049
        objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
2050
        self.assertEquals(objects, ['ο1'])
2051
        objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
2052
        self.assertEquals(objects, ['ο2'])
2053

    
2054
        meta = {'έτος':'2011'}
2055
        self.client.update_object_metadata('φάκελος', 'ο3', **meta)
2056
        meta = {'έτος':'2012'}
2057
        self.client.update_object_metadata('φάκελος', 'ο2', **meta)
2058
        objects = self.client.list_objects('φάκελος', meta='έτος<2012')
2059
        self.assertEquals(objects, ['ο3'])
2060
        objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
2061
        self.assertEquals(objects, ['ο2', 'ο3'])
2062
        objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
2063
        self.assertEquals(objects, '')
2064

    
2065
    def test_groups(self):
2066
        #create a group
2067
        groups = {'σεφς':'chazapis,διογένης'}
2068
        self.client.set_account_groups(**groups)
2069
        groups.update(self.initial_groups)
2070
        self.assertEqual(groups['σεφς'],
2071
                         self.client.retrieve_account_groups()['σεφς'])
2072

    
2073
        #check read access
2074
        self.client.create_container('φάκελος')
2075
        o = self.upload_random_data('φάκελος', 'ο1')
2076
        self.client.share_object('φάκελος', 'ο1', ['%s:σεφς' % get_user()])
2077
        chef = Pithos_Client(get_url(),
2078
                            '0009',
2079
                            'διογένης')
2080
        self.assert_not_raises_fault(403, chef.retrieve_object_metadata,
2081
                                     'φάκελος', 'ο1', account=get_user())
2082

    
2083
        #check write access
2084
        self.client.share_object('φάκελος', 'ο1', ['διογένης'], read=False)
2085
        new_data = get_random_data()
2086
        self.assert_not_raises_fault(403, chef.update_object,
2087
                                     'φάκελος', 'ο1', StringIO(new_data),
2088
                                     account=get_user())
2089

    
2090
        server_data = self.client.retrieve_object('φάκελος', 'ο1')
2091
        self.assertEqual(server_data[:len(o['data'])], o['data'])
2092
        self.assertEqual(server_data[len(o['data']):], new_data)
2093

    
2094
    def test_manifestation(self):
2095
        self.client.create_container('κουβάς')
2096
        prefix = 'μέρη/'
2097
        data = ''
2098
        for i in range(5):
2099
            part = '%s%d' %(prefix, i)
2100
            o = self.upload_random_data('κουβάς', part)
2101
            data += o['data']
2102

    
2103
        self.client.create_container('φάκελος')
2104
        manifest = '%s/%s' %('κουβάς', prefix)
2105
        self.client.create_manifestation('φάκελος', 'άπαντα', manifest)
2106

    
2107
        self.assert_object_exists('φάκελος', 'άπαντα')
2108
        self.assertEqual(data, self.client.retrieve_object('φάκελος',
2109
                                                           'άπαντα'))
2110

    
2111
        #wrong manifestation
2112
        self.client.create_manifestation('φάκελος', 'άπαντα', 'κουβάς/άκυρο')
2113
        self.assertEqual('', self.client.retrieve_object('φάκελος', 'άπαντα'))
2114

    
2115
    def test_update_from_another_object(self):
2116
        self.client.create_container('κουβάς')
2117
        src_data = self.upload_random_data('κουβάς', 'πηγή')['data']
2118
        initial_data = self.upload_random_data('κουβάς', 'νέο')['data']
2119
        source_object = '/%s/%s' % ('κουβάς', 'πηγή')
2120
        self.client.update_from_other_source('κουβάς', 'νέο', source_object)
2121

    
2122
        self.assertEqual(
2123
            self.client.retrieve_object('κουβάς', 'νέο'),
2124
            '%s%s' % (initial_data, self.client.retrieve_object('κουβάς', 'πηγή')))
2125

    
2126
class TestPermissions(BaseTestCase):
2127
    def setUp(self):
2128
        BaseTestCase.setUp(self)
2129

    
2130
        #create a group
2131
        self.authorized = ['chazapis', 'verigak', 'gtsouk']
2132
        groups = {'pithosdev':','.join(self.authorized)}
2133
        self.client.set_account_groups(**groups)
2134

    
2135
        self.container = 'c'
2136
        self.object = 'o'
2137
        self.client.create_container(self.container)
2138
        self.upload_random_data(self.container, self.object)
2139
        self.upload_random_data(self.container, self.object+'/')
2140
        self.upload_random_data(self.container, self.object+'/a')
2141
        self.upload_random_data(self.container, self.object+'a')
2142
        self.upload_random_data(self.container, self.object+'a/')
2143
        self.dir_content_types = ('application/directory', 'application/folder')
2144

    
2145
    def assert_read(self, authorized=[], any=False, depth=0):
2146
        for token, account in OTHER_ACCOUNTS.items():
2147
            cl = Pithos_Client(get_url(), token, account)
2148
            if account in authorized or any:
2149
                self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2150
                                             self.container, self.object,
2151
                                             account=get_user())
2152
            else:
2153
                self.assert_raises_fault(403, cl.retrieve_object_metadata,
2154
                                         self.container, self.object,
2155
                                         account=get_user())
2156

    
2157
        #check inheritance
2158
        meta = self.client.retrieve_object_metadata(self.container, self.object)
2159
        type = meta['content-type']
2160
        derivatives = self.client.list_objects(self.container, prefix=self.object)
2161
        #exclude the self.object
2162
        del derivatives[derivatives.index(self.object)]
2163
        for o in derivatives:
2164
            for token, account in OTHER_ACCOUNTS.items():
2165
                cl = Pithos_Client(get_url(), token, account)
2166
                prefix = self.object if self.object.endswith('/') else self.object+'/'
2167
                if (account in authorized or any) and \
2168
                (type in self.dir_content_types) and \
2169
                o.startswith(prefix):
2170
                    self.assert_not_raises_fault(403, cl.retrieve_object_metadata,
2171
                                             self.container, o, account=get_user())
2172
                else:
2173
                    self.assert_raises_fault(403, cl.retrieve_object_metadata,
2174
                                         self.container, o, account=get_user())
2175

    
2176
    def assert_write(self, authorized=[], any=False):
2177
        o_data = self.client.retrieve_object(self.container, self.object)
2178
        for token, account in OTHER_ACCOUNTS.items():
2179
            cl = Pithos_Client(get_url(), token, account)
2180
            new_data = get_random_data()
2181
            if account in authorized or any:
2182
                # test write access
2183
                self.assert_not_raises_fault(403, cl.update_object,
2184
                                             self.container, self.object, StringIO(new_data),
2185
                                             account=get_user())
2186
                try:
2187
                    # test read access
2188
                    server_data = cl.retrieve_object(self.container, self.object, account=get_user())
2189
                    self.assertEqual(o_data, server_data[:len(o_data)])
2190
                    self.assertEqual(new_data, server_data[len(o_data):])
2191
                    o_data = server_data
2192
                except Fault, f:
2193
                    self.failIf(f.status == 403)
2194
            else:
2195
                self.assert_raises_fault(403, cl.update_object,
2196
                                             self.container, self.object, StringIO(new_data),
2197
                                             account=get_user())
2198
        #check inheritance
2199
        meta = self.client.retrieve_object_metadata(self.container, self.object)
2200
        type = meta['content-type']
2201
        derivatives = self.client.list_objects(self.container, prefix=self.object)
2202
        #exclude the object
2203
        del derivatives[derivatives.index(self.object)]
2204
        for o in derivatives:
2205
            for token, account in OTHER_ACCOUNTS.items():
2206
                prefix = self.object if self.object.endswith('/') else self.object+'/'
2207
                cl = Pithos_Client(get_url(), token, account)
2208
                new_data = get_random_data()
2209
                if (account in authorized or any) and \
2210
                (type in self.dir_content_types) and \
2211
                o.startswith(prefix):
2212
                    # test write access
2213
                    self.assert_not_raises_fault(403, cl.update_object,
2214
                                                 self.container, o,
2215
                                                 StringIO(new_data),
2216
                                                 account=get_user())
2217
                    try:
2218
                        server_data = cl.retrieve_object(self.container, o, account=get_user())
2219
                        self.assertEqual(new_data, server_data[-len(new_data):])
2220
                    except Fault, f:
2221
                        self.failIf(f.status == 403)
2222
                else:
2223
                    self.assert_raises_fault(403, cl.update_object,
2224
                                                 self.container, o,
2225
                                                 StringIO(new_data),
2226
                                                 account=get_user())
2227

    
2228
    def test_group_read(self):
2229
        self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2230
        self.assert_read(authorized=self.authorized)
2231

    
2232
    def test_read_many(self):
2233
        self.client.share_object(self.container, self.object, self.authorized)
2234
        self.assert_read(authorized=self.authorized)
2235

    
2236
    def test_read_by_everyone(self):
2237
        self.client.share_object(self.container, self.object, ['*'])
2238
        self.assert_read(any=True)
2239

    
2240
    def test_read_directory(self):
2241
        for type in self.dir_content_types:
2242
            #change content type
2243
            self.client.move_object(self.container, self.object, self.container, self.object, content_type=type)
2244
            self.client.share_object(self.container, self.object, ['*'])
2245
            self.assert_read(any=True)
2246
            self.client.share_object(self.container, self.object, self.authorized)
2247
            self.assert_read(authorized=self.authorized)
2248
            self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()])
2249
            self.assert_read(authorized=self.authorized)
2250

    
2251
    def test_group_write(self):
2252
        self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2253
        self.assert_write(authorized=self.authorized)
2254

    
2255
    def test_write_many(self):
2256
        self.client.share_object(self.container, self.object, self.authorized, read=False)
2257
        self.assert_write(authorized=self.authorized)
2258

    
2259
    def test_write_by_everyone(self):
2260
        self.client.share_object(self.container, self.object, ['*'], read=False)
2261
        self.assert_write(any=True)
2262

    
2263
    def test_write_directory(self):
2264
        dir_content_types = ('application/directory', 'application/foler')
2265
        for type in dir_content_types:
2266
            #change content type
2267
            self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2268
            self.client.share_object(self.container, self.object, ['*'], read=False)
2269
            self.assert_write(any=True)
2270
            self.client.share_object(self.container, self.object, self.authorized, read=False)
2271
            self.assert_write(authorized=self.authorized)
2272
            self.client.share_object(self.container, self.object, ['%s:pithosdev' % get_user()], read=False)
2273
            self.assert_write(authorized=self.authorized)
2274

    
2275
    def test_shared_listing(self):
2276
        self.client.share_object(self.container, self.object, self.authorized)
2277

    
2278
        my_shared_containers = self.client.list_containers(shared=True)
2279
        self.assertEqual(['c'], my_shared_containers)
2280
        my_shared_objects = self.client.list_objects('c', shared=True)
2281
        self.assertEqual(['o'], my_shared_objects)
2282

    
2283
        dir_content_types = ('application/directory', 'application/foler')
2284
        for type in dir_content_types:
2285
            #change content type
2286
            self.client.move_object(self.container, self.object, self.container, self.object, content_type='application/folder')
2287
            my_shared_objects = self.client.list_objects('c', shared=True)
2288
            self.assertEqual(['o', 'o/', 'o/a'], my_shared_objects)
2289

    
2290
        for token, account in OTHER_ACCOUNTS.items():
2291
            if account in self.authorized:
2292
                self.other = Pithos_Client(get_url(), token, account)
2293
                self.assertTrue(get_user() in self.other.list_shared_by_others())
2294

    
2295
class TestPublish(BaseTestCase):
2296
    def test_publish(self):
2297
        self.client.create_container('c')
2298
        o_data = self.upload_random_data('c', 'o')['data']
2299
        self.client.publish_object('c', 'o')
2300
        meta = self.client.retrieve_object_metadata('c', 'o')
2301
        self.assertTrue('x-object-public' in meta)
2302
        url = meta['x-object-public']
2303

    
2304
        p = urlparse(get_url())
2305
        if p.scheme == 'http':
2306
            conn = HTTPConnection(p.netloc)
2307
        elif p.scheme == 'https':
2308
            conn = HTTPSConnection(p.netloc)
2309
        else:
2310
            raise Exception('Unknown URL scheme')
2311

    
2312
        conn.request('GET', url)
2313
        resp = conn.getresponse()
2314
        length = resp.getheader('content-length', None)
2315
        data = resp.read(length)
2316
        self.assertEqual(o_data, data)
2317

    
2318
class TestPolicies(BaseTestCase):
2319
    def test_none_versioning(self):
2320
        self.client.create_container('c', policies={'versioning':'none'})
2321
        o = self.upload_random_data('c', 'o')
2322
        meta = self.client.retrieve_object_metadata('c', 'o')
2323
        v = meta['x-object-version']
2324
        more_data = get_random_data()
2325
        self.client.update_object('c', 'o', StringIO(more_data))
2326
        vlist = self.client.retrieve_object_versionlist('c', 'o')
2327
        self.assert_raises_fault(404, self.client.retrieve_object_version,
2328
                                 'c', 'o', v)
2329
        data = self.client.retrieve_object('c', 'o')
2330
        end = len(o['data'])
2331
        self.assertEqual(data[:end], o['data'])
2332
        self.assertEqual(data[end:], more_data)
2333

    
2334
    def test_quota(self):
2335
        self.client.create_container('c', policies={'quota':'1'})
2336
        meta = self.client.retrieve_container_metadata('c')
2337
        self.assertEqual(meta['x-container-policy-quota'], '1')
2338
        self.assert_raises_fault(413, self.upload_random_data, 'c', 'o',
2339
                                 length=1024*1024+1)
2340

    
2341
    def test_quota_none(self):
2342
        self.client.create_container('c', policies={'quota':'0'})
2343
        meta = self.client.retrieve_container_metadata('c')
2344
        self.assertEqual(meta['x-container-policy-quota'], '0')
2345
        self.assert_not_raises_fault(413, self.upload_random_data, 'c', 'o',
2346
                                 length=1024*1024+1)
2347

    
2348
class AssertUUidInvariant(object):
2349
    def __init__(self, callable, *args, **kwargs):
2350
        self.callable = callable
2351
        self.args = args
2352
        self.kwargs = kwargs
2353

    
2354
    def __enter__(self):
2355
        self.map = self.callable(*self.args, **self.kwargs)
2356
        assert('x-object-uuid' in self.map)
2357
        self.uuid = self.map['x-object-uuid']
2358
        return self.map
2359

    
2360
    def __exit__(self, type, value, tb):
2361
        map = self.callable(*self.args, **self.kwargs)
2362
        assert('x-object-uuid' in self.map)
2363
        uuid = map['x-object-uuid']
2364
        assert(uuid == self.uuid)
2365

    
2366
class AssertMappingInvariant(object):
2367
    def __init__(self, callable, *args, **kwargs):
2368
        self.callable = callable
2369
        self.args = args
2370
        self.kwargs = kwargs
2371

    
2372
    def __enter__(self):
2373
        self.map = self.callable(*self.args, **self.kwargs)
2374
        return self.map
2375

    
2376
    def __exit__(self, type, value, tb):
2377
        map = self.callable(*self.args, **self.kwargs)
2378
        for k, v in self.map.items():
2379
            if is_date(v):
2380
                continue
2381
            assert(k in map)
2382
            assert v == map[k]
2383

    
2384
class AssertContentInvariant(object):
2385
    def __init__(self, callable, *args, **kwargs):
2386
        self.callable = callable
2387
        self.args = args
2388
        self.kwargs = kwargs
2389

    
2390
    def __enter__(self):
2391
        self.content = self.callable(*self.args, **self.kwargs)[2]
2392
        return self.content
2393

    
2394
    def __exit__(self, type, value, tb):
2395
        content = self.callable(*self.args, **self.kwargs)[2]
2396
        assert self.content == content
2397

    
2398
def get_content_splitted(response):
2399
    if response:
2400
        return response.content.split('\n')
2401

    
2402
def compute_md5_hash(data):
2403
    md5 = hashlib.md5()
2404
    offset = 0
2405
    md5.update(data)
2406
    return md5.hexdigest().lower()
2407

    
2408
def compute_block_hash(data, algorithm):
2409
    h = hashlib.new(algorithm)
2410
    h.update(data.rstrip('\x00'))
2411
    return h.hexdigest()
2412

    
2413
def get_random_data(length=500):
2414
    char_set = string.ascii_uppercase + string.digits
2415
    return ''.join(random.choice(char_set) for x in xrange(length))
2416

    
2417
def is_date(date):
2418
    MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
2419
    __D = r'(?P<day>\d{2})'
2420
    __D2 = r'(?P<day>[ \d]\d)'
2421
    __M = r'(?P<mon>\w{3})'
2422
    __Y = r'(?P<year>\d{4})'
2423
    __Y2 = r'(?P<year>\d{2})'
2424
    __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
2425
    RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
2426
    RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
2427
    ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
2428
    for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
2429
        m = regex.match(date)
2430
        if m is not None:
2431
            return True
2432
    return False
2433

    
2434
def strnextling(prefix):
2435
    """Return the first unicode string
2436
       greater than but not starting with given prefix.
2437
       strnextling('hello') -> 'hellp'
2438
    """
2439
    if not prefix:
2440
        ## all strings start with the null string,
2441
        ## therefore we have to approximate strnextling('')
2442
        ## with the last unicode character supported by python
2443
        ## 0x10ffff for wide (32-bit unicode) python builds
2444
        ## 0x00ffff for narrow (16-bit unicode) python builds
2445
        ## We will not autodetect. 0xffff is safe enough.
2446
        return unichr(0xffff)
2447
    s = prefix[:-1]
2448
    c = ord(prefix[-1])
2449
    if c >= 0xffff:
2450
        raise RuntimeError
2451
    s += unichr(c+1)
2452
    return s
2453

    
2454
o_names = ['kate.jpg',
2455
           'kate_beckinsale.jpg',
2456
           'How To Win Friends And Influence People.pdf',
2457
           'moms_birthday.jpg',
2458
           'poodle_strut.mov',
2459
           'Disturbed - Down With The Sickness.mp3',
2460
           'army_of_darkness.avi',
2461
           'the_mad.avi',
2462
           'photos/animals/dogs/poodle.jpg',
2463
           'photos/animals/dogs/terrier.jpg',
2464
           'photos/animals/cats/persian.jpg',
2465
           'photos/animals/cats/siamese.jpg',
2466
           'photos/plants/fern.jpg',
2467
           'photos/plants/rose.jpg',
2468
           'photos/me.jpg']
2469

    
2470

    
2471
def main():
2472
    if get_user() == 'test':
2473
        unittest.main(module='pithos.tools.test')
2474
    else:
2475
        print 'Will not run tests as any other user except \'test\' (current user: %s).' % get_user()
2476

    
2477

    
2478
if __name__ == "__main__":
2479
    main()
2480