Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / pithos_tests.py @ e7f5ebd0

History | View | Annotate | Download (44 kB)

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

    
34
"""
35
This is the burnin class that tests the Pithos functionality
36

37
"""
38

    
39
import random
40
from datetime import datetime
41
from tempfile import NamedTemporaryFile
42

    
43
from synnefo_tools.burnin.common import BurninTests, Proper
44
from kamaki.clients import ClientError
45

    
46

    
47
def sample_block(f, block):
48
    block_size = 4 * 1024 * 1024
49
    f.seek(block * block_size)
50
    ch = [f.read(1)]
51
    f.seek(block_size / 2, 1)
52
    ch.append(f.read(1))
53
    f.seek((block + 1) * block_size - 1)
54
    ch.append(f.read(1))
55
    return ch
56

    
57

    
58
# Too many public methods. pylint: disable-msg=R0904
59
class PithosTestSuite(BurninTests):
60
    """Test Pithos functionality"""
61
    containers = Proper(value=None)
62
    created_container = Proper(value=None)
63
    now_unformated = Proper(value=datetime.utcnow())
64
    obj_metakey = Proper(value=None)
65
    large_file = Proper(value=None)
66

    
67
    def test_005_account_head(self):
68
        """Test account HEAD"""
69
        self._set_pithos_account(self._get_uuid())
70
        pithos = self.clients.pithos
71
        r = pithos.account_head()
72
        self.assertEqual(r.status_code, 204)
73
        self.info('Returns 204')
74

    
75
        r = pithos.account_head(until='1000000000')
76
        self.assertEqual(r.status_code, 204)
77
        datestring = unicode(r.headers['x-account-until-timestamp'])
78
        self.assertEqual(u'Sun, 09 Sep 2001 01:46:40 GMT', datestring)
79
        self.assertTrue('x-account-policy-quota' in r.headers)
80
        self.info('Until and policy quota exist')
81

    
82
        for format in pithos.DATE_FORMATS:
83
            now_formated = self.now_unformated.strftime(format)
84
            r1 = pithos.account_head(
85
                if_modified_since=now_formated, success=(204, 304, 412))
86
            r2 = pithos.account_head(
87
                if_unmodified_since=now_formated, success=(204, 304, 412))
88
            self.assertNotEqual(r1.status_code, r2.status_code)
89
        self.info('If_(un)modified_since is OK')
90

    
91
    def test_010_account_get(self):
92
        """Test account GET"""
93
        self.info('Preparation')
94
        pithos = self.clients.pithos
95
        for i in range(1, 3):
96
            cont_name = "cont%s_%s%s" % (
97
                i, self.run_id or 0, random.randint(1000, 9999))
98
            self._create_pithos_container(cont_name)
99
        pithos.container, obj = cont_name, 'shared_file'
100
        pithos.create_object(obj)
101
        pithos.set_object_sharing(obj, read_permission='*')
102
        self.info('Created object /%s/%s' % (cont_name, obj))
103

    
104
        #  Try to re-create the same container
105
        pithos.create_container(cont_name)
106

    
107
        r = pithos.list_containers()
108
        fullLen = len(r)
109
        self.assertTrue(fullLen > 2)
110
        self.info('Normal use is OK')
111

    
112
        cnames = [c['name'] for c in r]
113
        self.assertEqual(sorted(list(set(cnames))), sorted(cnames))
114
        self.info('Containers have unique names')
115

    
116
        r = pithos.account_get(limit=1)
117
        self.assertEqual(len(r.json), 1)
118
        self.info('Limit works')
119

    
120
        r = pithos.account_get(marker='cont')
121
        cont1, cont3 = r.json[0], r.json[2]
122
        self.info('Marker works')
123

    
124
        r = pithos.account_get(limit=2, marker='cont')
125
        conames = [container['name'] for container in r.json if (
126
            container['name'].lower().startswith('cont'))]
127
        self.assertTrue(cont1['name'] in conames)
128
        self.assertFalse(cont3['name'] in conames)
129
        self.info('Marker-limit combination works')
130

    
131
        r = pithos.account_get(show_only_shared=True)
132
        self.assertTrue(cont_name in [c['name'] for c in r.json])
133
        self.info('Show-only-shared works')
134

    
135
        r = pithos.account_get(until=1342609206.0)
136
        self.assertTrue(len(r.json) <= fullLen)
137
        self.info('Until works')
138

    
139
        for format in pithos.DATE_FORMATS:
140
            now_formated = self.now_unformated.strftime(format)
141
            r1 = pithos.account_get(
142
                if_modified_since=now_formated, success=(200, 304, 412))
143
            r2 = pithos.account_get(
144
                if_unmodified_since=now_formated, success=(200, 304, 412))
145
            self.assertNotEqual(r1.status_code, r2.status_code)
146
        self.info('If_(un)modified_since is OK')
147

    
148
    def test_015_account_post(self):
149
        """Test account POST"""
150
        pithos = self.clients.pithos
151
        r = pithos.account_post()
152
        self.assertEqual(r.status_code, 202)
153
        self.info('Status code is OK')
154

    
155
        rand_num = '%s%s' % (self.run_id or 0, random.randint(1000, 9999))
156
        grpName = 'grp%s' % rand_num
157

    
158
        u1, u2 = pithos.account, 'invalid-user-uuid-%s' % rand_num
159
        self.assertRaises(
160
            ClientError, pithos.set_account_group, grpName, [u1, u2])
161
        self.info('Invalid uuid is handled correctly')
162

    
163
        pithos.set_account_group(grpName, [u1])
164
        r = pithos.get_account_group()
165
        self.assertEqual(r['x-account-group-' + grpName], '%s' % u1)
166
        self.info('Account group is OK')
167
        pithos.del_account_group(grpName)
168
        r = pithos.get_account_group()
169
        self.assertTrue('x-account-group-' + grpName not in r)
170
        self.info('Removed account group')
171

    
172
        mprefix = 'meta%s' % rand_num
173
        pithos.set_account_meta({
174
            mprefix + '1': 'v1', mprefix + '2': 'v2'})
175
        r = pithos.get_account_meta()
176
        self.assertEqual(r['x-account-meta-' + mprefix + '1'], 'v1')
177
        self.assertEqual(r['x-account-meta-' + mprefix + '2'], 'v2')
178
        self.info('Account meta is OK')
179

    
180
        pithos.del_account_meta(mprefix + '1')
181
        r = pithos.get_account_meta()
182
        self.assertTrue('x-account-meta-' + mprefix + '1' not in r)
183
        self.assertTrue('x-account-meta-' + mprefix + '2' in r)
184
        self.info('Selective removal of account meta is OK')
185

    
186
        pithos.del_account_meta(mprefix + '2')
187
        r = pithos.get_account_meta()
188
        self.assertTrue('x-account-meta-' + mprefix + '2' not in r)
189
        self.info('Temporary account meta are removed')
190

    
191
    def test_020_container_head(self):
192
        """Test container HEAD"""
193
        pithos = self.clients.pithos
194
        r = pithos.container_head()
195
        self.assertEqual(r.status_code, 204)
196
        self.info('Status code is OK')
197

    
198
        r = pithos.container_head(until=1000000, success=(204, 404))
199
        self.assertEqual(r.status_code, 404)
200
        self.info('Until works')
201

    
202
        for format in pithos.DATE_FORMATS:
203
            now_formated = self.now_unformated.strftime(format)
204
            r1 = pithos.container_head(
205
                if_modified_since=now_formated, success=(204, 304, 412))
206
            r2 = pithos.container_head(
207
                if_unmodified_since=now_formated, success=(204, 304, 412))
208
            self.assertNotEqual(r1.status_code, r2.status_code)
209

    
210
        k = 'metakey%s' % random.randint(1000, 9999)
211
        pithos.set_container_meta({k: 'our value'})
212
        r = pithos.get_container_meta()
213
        k = 'x-container-meta-%s' % k
214
        self.assertIn(k, r)
215
        self.assertEqual('our value', r[k])
216
        self.info('Container meta exists')
217

    
218
        self.obj_metakey = 'metakey%s' % random.randint(1000, 9999)
219
        obj = 'object_with_meta'
220
        pithos.create_object(obj)
221
        pithos.set_object_meta(obj, {self.obj_metakey: 'our value'})
222
        r = pithos.get_container_object_meta()
223
        self.assertIn('x-container-object-meta', r)
224
        self.assertIn(
225
            self.obj_metakey, r['x-container-object-meta'].lower())
226
        self.info('Container object meta exists')
227

    
228
    def test_025_container_get(self):
229
        """Test container GET"""
230
        pithos = self.clients.pithos
231

    
232
        r = pithos.container_get()
233
        self.assertEqual(r.status_code, 200)
234
        self.info('Status code is OK')
235

    
236
        fullLen = len(r.json)
237
        self.assertGreater(fullLen, 0)
238
        self.info('There are enough (%s) containers' % fullLen)
239

    
240
        obj1 = 'test%s' % random.randint(1000, 9999)
241
        pithos.create_object(obj1)
242
        obj2 = 'test%s' % random.randint(1000, 9999)
243
        pithos.create_object(obj2)
244
        obj3 = 'another%s.test' % random.randint(1000, 9999)
245
        pithos.create_object(obj3)
246

    
247
        r = pithos.container_get(prefix='test')
248
        self.assertTrue(len(r.json) > 1)
249
        test_objects = [o for o in r.json if o['name'].startswith('test')]
250
        self.assertEqual(len(r.json), len(test_objects))
251
        self.info('Prefix is OK')
252

    
253
        r = pithos.container_get(limit=1)
254
        self.assertEqual(len(r.json), 1)
255
        self.info('Limit is OK')
256

    
257
        r = pithos.container_get(marker=obj3[:-5])
258
        self.assertTrue(len(r.json) > 1)
259
        aoobjects = [obj for obj in r.json if obj['name'] > obj3[:-5]]
260
        self.assertEqual(len(r.json), len(aoobjects))
261
        self.info('Marker is OK')
262

    
263
        r = pithos.container_get(prefix=obj3, delimiter='.')
264
        self.assertTrue(fullLen > len(r.json))
265
        self.info('Delimiter is OK')
266

    
267
        r = pithos.container_get(path='/')
268
        fullLen += 3
269
        self.assertEqual(fullLen, len(r.json))
270
        self.info('Path is OK')
271

    
272
        r = pithos.container_get(format='xml')
273
        self.assertEqual(r.text.split()[4], 'name="' + pithos.container + '">')
274
        self.info('Format is OK')
275

    
276
        r = pithos.container_get(meta=[self.obj_metakey, ])
277
        self.assertTrue(len(r.json) > 0)
278
        self.info('Meta is OK')
279

    
280
        r = pithos.container_get(show_only_shared=True)
281
        self.assertTrue(len(r.json) < fullLen)
282
        self.info('Show-only-shared is OK')
283

    
284
        try:
285
            r = pithos.container_get(until=1000000000)
286
            datestring = unicode(r.headers['x-account-until-timestamp'])
287
            self.assertEqual(u'Sun, 09 Sep 2001 01:46:40 GMT', datestring)
288
            self.info('Until is OK')
289
        except ClientError:
290
            pass
291

    
292
    def test_030_container_put(self):
293
        """Test container PUT"""
294
        pithos = self.clients.pithos
295
        pithos.container = 'cont%s%s' % (
296
            self.run_id or 0, random.randint(1000, 9999))
297
        self.temp_containers.append(pithos.container)
298

    
299
        r = pithos.create_container()
300
        self.assertTrue(isinstance(r, dict))
301

    
302
        r = pithos.get_container_limit(pithos.container)
303
        cquota = r.values()[0]
304
        newquota = 2 * int(cquota)
305
        self.info('Limit is OK')
306
        pithos.del_container()
307

    
308
        r = pithos.create_container(sizelimit=newquota)
309
        self.assertTrue(isinstance(r, dict))
310

    
311
        r = pithos.get_container_limit(pithos.container)
312
        xquota = int(r.values()[0])
313
        self.assertEqual(newquota, xquota)
314
        self.info('Can set container limit')
315
        pithos.del_container()
316

    
317
        r = pithos.create_container(versioning='auto')
318
        self.assertTrue(isinstance(r, dict))
319

    
320
        r = pithos.get_container_versioning(pithos.container)
321
        nvers = r.values()[0]
322
        self.assertEqual('auto', nvers)
323
        self.info('Versioning=auto is OK')
324
        pithos.del_container()
325

    
326
        r = pithos.container_put(versioning='none')
327
        self.assertEqual(r.status_code, 201)
328

    
329
        r = pithos.get_container_versioning(pithos.container)
330
        nvers = r.values()[0]
331
        self.assertEqual('none', nvers)
332
        self.info('Versioning=none is OK')
333
        pithos.del_container()
334

    
335
        r = pithos.create_container(metadata={'m1': 'v1', 'm2': 'v2'})
336
        self.assertTrue(isinstance(r, dict))
337

    
338
        r = pithos.get_container_meta(pithos.container)
339
        self.assertTrue('x-container-meta-m1' in r)
340
        self.assertEqual(r['x-container-meta-m1'], 'v1')
341
        self.assertTrue('x-container-meta-m2' in r)
342
        self.assertEqual(r['x-container-meta-m2'], 'v2')
343

    
344
        r = pithos.container_put(metadata={'m1': '', 'm2': 'v2a'})
345
        self.assertEqual(r.status_code, 202)
346

    
347
        r = pithos.get_container_meta(pithos.container)
348
        self.assertTrue('x-container-meta-m1' not in r)
349
        self.assertTrue('x-container-meta-m2' in r)
350
        self.assertEqual(r['x-container-meta-m2'], 'v2a')
351
        self.info('Container meta is OK')
352

    
353
        pithos.del_container_meta(pithos.container)
354

    
355
    def test_035_container_post(self):
356
        """Test container POST"""
357
        pithos = self.clients.pithos
358

    
359
        r = pithos.container_post()
360
        self.assertEqual(r.status_code, 202)
361
        self.info('Status is OK')
362

    
363
        pithos.set_container_meta({'m1': 'v1', 'm2': 'v2'})
364
        r = pithos.get_container_meta(pithos.container)
365
        self.assertTrue('x-container-meta-m1' in r)
366
        self.assertEqual(r['x-container-meta-m1'], 'v1')
367
        self.assertTrue('x-container-meta-m2' in r)
368
        self.assertEqual(r['x-container-meta-m2'], 'v2')
369
        self.info('Set metadata works')
370

    
371
        r = pithos.del_container_meta('m1')
372
        r = pithos.set_container_meta({'m2': 'v2a'})
373
        r = pithos.get_container_meta(pithos.container)
374
        self.assertTrue('x-container-meta-m1' not in r)
375
        self.assertTrue('x-container-meta-m2' in r)
376
        self.assertEqual(r['x-container-meta-m2'], 'v2a')
377
        self.info('Delete metadata works')
378

    
379
        r = pithos.get_container_limit(pithos.container)
380
        cquota = r.values()[0]
381
        newquota = 2 * int(cquota)
382
        r = pithos.set_container_limit(newquota)
383
        r = pithos.get_container_limit(pithos.container)
384
        xquota = int(r.values()[0])
385
        self.assertEqual(newquota, xquota)
386
        self.info('Set quota works')
387

    
388
        pithos.set_container_versioning('auto')
389
        r = pithos.get_container_versioning(pithos.container)
390
        nvers = r.values()[0]
391
        self.assertEqual('auto', nvers)
392
        pithos.set_container_versioning('none')
393
        r = pithos.get_container_versioning(pithos.container)
394
        nvers = r.values()[0]
395
        self.assertEqual('none', nvers)
396
        self.info('Set versioning works')
397

    
398
        f = self._create_large_file(1024 * 1024 * 100)
399
        self.large_file = f
400
        self.info('Created file %s of 100 MB' % f.name)
401

    
402
        pithos.create_directory('dir')
403
        self.info('Upload the file ...')
404
        r = pithos.upload_object('/dir/sample.file', f)
405
        for term in ('content-length', 'content-type', 'x-object-version'):
406
            self.assertTrue(term in r)
407
        r = pithos.get_object_info('/dir/sample.file')
408
        self.assertTrue(int(r['content-length']) > 100000000)
409
        self.info('Made remote directory /dir and object /dir/sample.file')
410

    
411
        """What is tranfer_encoding? What should I check about it? """
412
        #TODO
413

    
414
        obj = 'object_with_meta'
415
        pithos.container = self.temp_containers[-2]
416
        r = pithos.object_post(
417
            obj, update='False', metadata={'newmeta': 'newval'})
418

    
419
        r = pithos.get_object_info(obj)
420
        self.assertTrue('x-object-meta-newmeta' in r)
421
        self.assertFalse('x-object-meta-%s' % self.obj_metakey not in r)
422
        self.info('Metadata with update=False works')
423

    
424
    def test_040_container_delete(self):
425
        """Test container DELETE"""
426
        pithos = self.clients.pithos
427

    
428
        r = pithos.container_delete(success=409)
429
        self.assertEqual(r.status_code, 409)
430
        self.assertRaises(ClientError, pithos.container_delete)
431
        self.info('Successfully failed to delete non-empty container')
432

    
433
        r = pithos.container_delete(until='1000000000')
434
        self.assertEqual(r.status_code, 204)
435
        self.info('Successfully failed to delete old-timestamped container')
436

    
437
        obj_names = [o['name'] for o in pithos.container_get().json]
438
        pithos.del_container(delimiter='/')
439
        r = pithos.container_get()
440
        self.assertEqual(len(r.json), 0)
441
        self.info('Successfully emptied container')
442

    
443
        for obj in obj_names:
444
            r = pithos.get_object_versionlist(obj)
445
            self.assertTrue(len(r) > 0)
446
        self.info('Versions are still there')
447

    
448
        pithos.purge_container()
449
        for obj in obj_names:
450
            self.assertRaises(ClientError, pithos.get_object_versionlist, obj)
451
        self.info('Successfully purged container')
452

    
453
        self.temp_containers.remove(pithos.container)
454
        pithos.container = self.temp_containers[-1]
455

    
456
    def test_045_object_head(self):
457
        """Test object HEAD"""
458
        pithos = self.clients.pithos
459

    
460
        obj = 'dir/sample.file'
461
        r = pithos.object_head(obj)
462
        self.assertEqual(r.status_code, 200)
463
        self.info('Status code is OK')
464
        etag = r.headers['etag']
465
        real_version = r.headers['x-object-version']
466

    
467
        self.assertRaises(ClientError, pithos.object_head, obj, version=-10)
468
        r = pithos.object_head(obj, version=real_version)
469
        self.assertEqual(r.headers['x-object-version'], real_version)
470
        self.info('Version works')
471

    
472
        r = pithos.object_head(obj, if_etag_match=etag)
473
        self.assertEqual(r.status_code, 200)
474
        self.info('if-etag-match is OK')
475

    
476
        r = pithos.object_head(
477
            obj, if_etag_not_match=etag, success=(200, 412, 304))
478
        self.assertNotEqual(r.status_code, 200)
479
        self.info('if-etag-not-match works')
480

    
481
        r = pithos.object_head(
482
            obj, version=real_version, if_etag_match=etag, success=200)
483
        self.assertEqual(r.status_code, 200)
484
        self.info('Version with if-etag-match works')
485

    
486
        for format in pithos.DATE_FORMATS:
487
            now_formated = self.now_unformated.strftime(format)
488
            r1 = pithos.object_head(
489
                obj, if_modified_since=now_formated, success=(200, 304, 412))
490
            r2 = pithos.object_head(
491
                obj, if_unmodified_since=now_formated, success=(200, 304, 412))
492
            self.assertNotEqual(r1.status_code, r2.status_code)
493
        self.info('if-(un)modified-since works')
494

    
495
    def test_050_object_get(self):
496
        """Test object GET"""
497
        pithos = self.clients.pithos
498
        obj = 'dir/sample.file'
499

    
500
        r = pithos.object_get(obj)
501
        self.assertEqual(r.status_code, 200)
502
        self.info('Status code is OK')
503

    
504
        osize = int(r.headers['content-length'])
505
        etag = r.headers['etag']
506

    
507
        r = pithos.object_get(obj, hashmap=True)
508
        self.assertEqual(
509
            set(('hashes', 'block_size', 'block_hash', 'bytes')), set(r.json))
510
        self.info('Hashmap works')
511
        hash0 = r.json['hashes'][0]
512

    
513
        r = pithos.object_get(obj, format='xml', hashmap=True)
514
        self.assertTrue(r.text.split('hash>')[1].startswith(hash0))
515
        self.info('Hashmap with XML format works')
516

    
517
        rangestr = 'bytes=%s-%s' % (osize / 3, osize / 2)
518
        r = pithos.object_get(obj, data_range=rangestr, success=(200, 206))
519
        partsize = int(r.headers['content-length'])
520
        self.assertTrue(0 < partsize and partsize <= 1 + osize / 3)
521
        self.info('Range x-y works')
522
        orig = r.text
523

    
524
        rangestr = 'bytes=%s' % (osize / 3)
525
        r = pithos.object_get(
526
            obj, data_range=rangestr, if_range=True, success=(200, 206))
527
        partsize = int(r.headers['content-length'])
528
        self.assertTrue(partsize, 1 + (osize / 3))
529
        diff = set(r.text).symmetric_difference(set(orig[:partsize]))
530
        self.assertEqual(len(diff), 0)
531
        self.info('Range x works')
532

    
533
        rangestr = 'bytes=-%s' % (osize / 3)
534
        r = pithos.object_get(
535
            obj, data_range=rangestr, if_range=True, success=(200, 206))
536
        partsize = int(r.headers['content-length'])
537
        self.assertTrue(partsize, osize / 3)
538
        diff = set(r.text).symmetric_difference(set(orig[-partsize:]))
539
        self.assertEqual(len(diff), 0)
540
        self.info('Range -x works')
541

    
542
        r = pithos.object_get(obj, if_etag_match=etag)
543
        self.assertEqual(r.status_code, 200)
544
        self.info('if-etag-match works')
545

    
546
        r = pithos.object_get(obj, if_etag_not_match=etag + 'LALALA')
547
        self.assertEqual(r.status_code, 200)
548
        self.info('if-etag-not-match works')
549

    
550
        for format in pithos.DATE_FORMATS:
551
            now_formated = self.now_unformated.strftime(format)
552
            r1 = pithos.object_get(
553
                obj, if_modified_since=now_formated, success=(200, 304, 412))
554
            r2 = pithos.object_get(
555
                obj, if_unmodified_since=now_formated, success=(200, 304, 412))
556
            self.assertNotEqual(r1.status_code, r2.status_code)
557
        self.info('if(un)modified-since works')
558

    
559
        obj, dnl_f = 'dir/sample.file', NamedTemporaryFile()
560
        self.info('Download %s as %s ...' % (obj, dnl_f.name))
561
        pithos.download_object(obj, dnl_f)
562
        self.info('Download is completed')
563

    
564
        f_size = len(orig)
565
        for pos in (0, f_size / 2, f_size - 128):
566
            dnl_f.seek(pos)
567
            self.large_file.seek(pos)
568
            self.assertEqual(self.large_file.read(64), dnl_f.read(64))
569
        self.info('Sampling shows that files match')
570

    
571
        self.info('Create a boring file of 42 blocks...')
572
        bor_f = self._create_boring_file(42)
573
        trg_fname = 'dir/uploaded.file'
574
        self.info('Now, upload the boring file as %s...' % trg_fname)
575
        pithos.upload_object(trg_fname, bor_f)
576
        self.info('Boring file %s is uploaded as %s' % (bor_f.name, trg_fname))
577
        dnl_f = NamedTemporaryFile()
578
        self.info('Download boring file as %s' % dnl_f.name)
579
        pithos.download_object(trg_fname, dnl_f)
580
        self.info('File is downloaded')
581

    
582
        for i in range(42):
583
            self.assertEqual(sample_block(bor_f, i), sample_block(dnl_f, i))
584

    
585
    def test_055_object_put(self):
586
        """Test object PUT"""
587
        pithos = self.clients.pithos
588
        obj = 'sample.file'
589

    
590
        pithos.create_object(obj + '.FAKE')
591
        r = pithos.get_object_info(obj + '.FAKE')
592
        self.assertEqual(
593
            set(r['content-type']), set('application/octer-stream'))
594
        self.info('Simple call creates a new object correctly')
595

    
596
        r = pithos.object_put(
597
            obj,
598
            data='a',
599
            content_type='application/octer-stream',
600
            permissions=dict(
601
                read=['accX:groupA', 'u1', 'u2'],
602
                write=['u2', 'u3']),
603
            metadata=dict(key1='val1', key2='val2'),
604
            content_encoding='UTF-8',
605
            content_disposition='attachment; filename="fname.ext"')
606
        self.assertEqual(r.status_code, 201)
607
        self.info('Status code is OK')
608
        etag = r.headers['etag']
609

    
610
        r = pithos.get_object_info(obj)
611
        self.assertTrue('content-disposition' in r)
612
        self.assertEqual(
613
            r['content-disposition'], 'attachment; filename="fname.ext"')
614
        self.info('Content-disposition is OK')
615

    
616
        sharing = r['x-object-sharing'].split('; ')
617
        self.assertTrue(sharing[0].startswith('read='))
618
        read = set(sharing[0][5:].split(','))
619
        self.assertEqual(set(('u1', 'accx:groupa')), read)
620
        self.assertTrue(sharing[1].startswith('write='))
621
        write = set(sharing[1][6:].split(','))
622
        self.assertEqual(set(('u2', 'u3')), write)
623
        self.info('Permissions are OK')
624

    
625
        r = pithos.get_object_meta(obj)
626
        self.assertEqual(r['x-object-meta-key1'], 'val1')
627
        self.assertEqual(r['x-object-meta-key2'], 'val2')
628
        self.info('Meta are OK')
629

    
630
        pithos.object_put(
631
            obj,
632
            if_etag_match=etag,
633
            data='b',
634
            content_type='application/octet-stream',
635
            public=True)
636
        self.info('If-etag-match is OK')
637

    
638
        r = pithos.object_get(obj)
639
        self.assertTrue('x-object-public' in r.headers)
640
        self.info('Publishing works')
641

    
642
        etag = r.headers['etag']
643
        self.assertEqual(r.text, 'b')
644
        self.info('Remote object content is correct')
645

    
646
        r = pithos.object_put(
647
            obj,
648
            if_etag_not_match=etag,
649
            data='c',
650
            content_type='application/octet-stream',
651
            success=(201, 412))
652
        self.assertEqual(r.status_code, 412)
653
        self.info('If-etag-not-match is OK')
654

    
655
        r = pithos.get_object_info('dir')
656
        self.assertEqual(r['content-type'], 'application/directory')
657
        self.info('Directory has been created correctly')
658

    
659
        r = pithos.object_put(
660
            '%s_v2' % obj,
661
            format=None,
662
            copy_from='/%s/%s' % (pithos.container, obj),
663
            content_encoding='application/octet-stream',
664
            source_account=pithos.account,
665
            content_length=0,
666
            success=201)
667
        self.assertEqual(r.status_code, 201)
668
        r1 = pithos.get_object_info(obj)
669
        r2 = pithos.get_object_info('%s_v2' % obj)
670
        self.assertEqual(r1['x-object-hash'], r2['x-object-hash'])
671
        self.info('Object has being copied in same container, OK')
672

    
673
        pithos.copy_object(
674
            src_container=pithos.container,
675
            src_object=obj,
676
            dst_container=self.temp_containers[-2],
677
            dst_object='%s_new' % obj)
678
        pithos.container = self.temp_containers[-2]
679
        r1 = pithos.get_object_info('%s_new' % obj)
680
        pithos.container = self.temp_containers[-1]
681
        r2 = pithos.get_object_info(obj)
682
        self.assertEqual(r1['x-object-hash'], r2['x-object-hash'])
683
        self.info('Object has being copied in another container, OK')
684

    
685
        fromstr = '/%s/%s_new' % (self.temp_containers[-2], obj)
686
        r = pithos.object_put(
687
            obj,
688
            format=None,
689
            copy_from=fromstr,
690
            content_encoding='application/octet-stream',
691
            source_account=pithos.account,
692
            content_length=0,
693
            success=201)
694
        self.assertEqual(r.status_code, 201)
695
        self.info('Cross container put accepts content_encoding')
696

    
697
        r = pithos.get_object_info(obj)
698
        self.assertEqual(r['etag'], etag)
699
        self.info('Etag is OK')
700

    
701
        r = pithos.object_put(
702
            '%s_v3' % obj,
703
            format=None,
704
            move_from=fromstr,
705
            content_encoding='application/octet-stream',
706
            source_account='nonExistendAddress@NeverLand.com',
707
            content_length=0,
708
            success=(403, ))
709
        self.info('Fake source account is handled correctly')
710

    
711
        r1 = pithos.get_object_info(obj)
712
        pithos.container = self.temp_containers[-2]
713
        pithos.move_object(
714
            src_container=self.temp_containers[-1],
715
            src_object=obj,
716
            dst_container=pithos.container,
717
            dst_object=obj + '_new')
718
        r0 = pithos.get_object_info(obj + '_new')
719
        self.assertEqual(r1['x-object-hash'], r0['x-object-hash'])
720
        self.info('Cross container move is OK')
721

    
722
        pithos.container = self.temp_containers[-1]
723
        pithos.create_container(versioning='auto')
724
        pithos.upload_from_string(obj, 'first version')
725
        source_hashmap = pithos.get_object_hashmap(obj)['hashes']
726
        pithos.upload_from_string(obj, 'second version')
727
        pithos.upload_from_string(obj, 'third version')
728
        versions = pithos.get_object_versionlist(obj)
729
        self.assertEqual(len(versions), 3)
730
        vers0 = versions[0][0]
731

    
732
        pithos.container = self.temp_containers[-2]
733
        pithos.object_put(
734
            obj,
735
            format=None,
736
            move_from='/%s/%s' % (self.temp_containers[-1], obj),
737
            source_version=vers0,
738
            content_encoding='application/octet-stream',
739
            content_length=0, success=201)
740
        target_hashmap = pithos.get_object_hashmap(obj)['hashes']
741
        self.info('Source-version is probably not OK (Check bug #4963)')
742
        source_hashmap, target_hashmap = source_hashmap, target_hashmap
743
        #  Comment out until it's fixed
744
        #  self.assertEqual(source_hashmap, target_hashmap)
745
        #  self.info('Source-version is OK')
746

    
747
        mobj = 'manifest.test'
748
        txt = ''
749
        for i in range(10):
750
            txt += '%s' % i
751
            pithos.object_put(
752
                '%s/%s' % (mobj, i),
753
                data='%s' % i,
754
                content_length=1,
755
                success=201,
756
                content_type='application/octet-stream',
757
                content_encoding='application/octet-stream')
758
        pithos.object_put(
759
            mobj,
760
            content_length=0,
761
            content_type='application/octet-stream',
762
            manifest='%s/%s' % (pithos.container, mobj))
763
        r = pithos.object_get(mobj)
764
        self.assertEqual(r.text, txt)
765
        self.info('Manifest file creation works')
766

    
767
        f = self._create_large_file(1024 * 10)
768
        pithos.upload_object('sample.file', f)
769
        r = pithos.get_object_info('sample.file')
770
        self.assertEqual(int(r['content-length']), 10240)
771
        self.info('Overwrite is OK')
772

    
773
        """MISSING: test transfer-encoding?"""
774

    
775
    def test_060_object_copy(self):
776
        """Test object COPY"""
777
        pithos = self.clients.pithos
778
        obj, trg = 'source.file2copy', 'copied.file'
779
        data = '{"key1":"val1", "key2":"val2"}'
780

    
781
        r = pithos.object_put(
782
            obj,
783
            content_type='application/octet-stream',
784
            data=data,
785
            metadata=dict(mkey1='mval1', mkey2='mval2'),
786
            permissions=dict(
787
                read=['accX:groupA', 'u1', 'u2'],
788
                write=['u2', 'u3']),
789
            content_disposition='attachment; filename="fname.ext"')
790
        self.info('Prepared a file /%s/%s' % (pithos.container, obj))
791

    
792
        r = pithos.object_copy(
793
            obj,
794
            destination='/%s/%s' % (pithos.container, trg),
795
            ignore_content_type=False, content_type='application/json',
796
            metadata={'mkey2': 'mval2a', 'mkey3': 'mval3'},
797
            permissions={'write': ['u5', 'accX:groupB']})
798
        self.assertEqual(r.status_code, 201)
799
        self.info('Status code is OK')
800

    
801
        r = pithos.get_object_info(trg)
802
        self.assertTrue('content-disposition' in r)
803
        self.info('Content-disposition is OK')
804

    
805
        self.assertEqual(r['x-object-meta-mkey1'], 'mval1')
806
        self.assertEqual(r['x-object-meta-mkey2'], 'mval2a')
807
        self.assertEqual(r['x-object-meta-mkey3'], 'mval3')
808
        self.info('Metadata are OK')
809

    
810
        r = pithos.get_object_sharing(trg)
811
        self.assertFalse('read' in r or 'u2' in r['write'])
812
        self.assertTrue('accx:groupb' in r['write'])
813
        self.info('Sharing is OK')
814

    
815
        r = pithos.object_copy(
816
            obj,
817
            destination='/%s/%s' % (pithos.container, obj),
818
            content_encoding='utf8',
819
            content_type='application/json',
820
            destination_account='nonExistendAddress@NeverLand.com',
821
            success=(201, 404))
822
        self.assertEqual(r.status_code, 404)
823
        self.info('Non existing UUID correctly causes a 404')
824

    
825
        r = pithos.object_copy(
826
            obj,
827
            destination='/%s/%s' % (self.temp_containers[-1], obj),
828
            content_encoding='utf8',
829
            content_type='application/json')
830
        self.assertEqual(r.status_code, 201)
831
        self.assertEqual(
832
            r.headers['content-type'],
833
            'application/json; charset=UTF-8')
834

    
835
        pithos.container = self.temp_containers[-1]
836
        r = pithos.object_get(obj)
837
        etag = r.headers['etag']
838
        ctype = r.headers['content-type']
839
        self.assertEqual(ctype, 'application/json')
840
        self.info('Cross container copy w. content-type/encoding is OK')
841

    
842
        r = pithos.object_copy(
843
            obj,
844
            destination='/%s/%s0' % (pithos.container, obj),
845
            ignore_content_type=True,
846
            content_type='text/x-python')
847
        self.assertEqual(r.status_code, 201)
848
        self.assertNotEqual(r.headers['content-type'], 'application/json')
849
        r = pithos.object_get(obj + '0')
850
        self.assertNotEqual(r.headers['content-type'], 'text/x-python')
851

    
852
        r = pithos.object_copy(
853
            obj,
854
            destination='/%s/%s1' % (pithos.container, obj),
855
            if_etag_match=etag)
856
        self.assertEqual(r.status_code, 201)
857
        self.info('if-etag-match is OK')
858

    
859
        r = pithos.object_copy(
860
            obj,
861
            destination='/%s/%s2' % (pithos.container, obj),
862
            if_etag_not_match='lalala')
863
        self.assertEqual(r.status_code, 201)
864
        self.info('if-etag-not-match is OK')
865

    
866
        r = pithos.object_copy(
867
            '%s2' % obj,
868
            destination='/%s/%s3' % (pithos.container, obj),
869
            format='xml',
870
            public=True)
871
        self.assertEqual(r.status_code, 201)
872
        self.assertTrue('xml' in r.headers['content-type'])
873

    
874
        r = pithos.get_object_info(obj + '3')
875
        self.assertTrue('x-object-public' in r)
876
        self.info('Publish, format and source-version are OK')
877

    
878
    def test_065_object_move(self):
879
        """Test object MOVE"""
880
        pithos = self.clients.pithos
881
        obj = 'source.file2move'
882
        data = '{"key1": "val1", "key2": "val2"}'
883

    
884
        r = pithos.object_put(
885
            obj,
886
            content_type='application/octet-stream',
887
            data=data,
888
            metadata=dict(mkey1='mval1', mkey2='mval2'),
889
            permissions=dict(
890
                read=['accX:groupA', 'u1', 'u2'],
891
                write=['u2', 'u3']))
892
        self.info('Prepared a file /%s/%s' % (pithos.container, obj))
893

    
894
        r = pithos.object_move(
895
            obj,
896
            destination='/%s/%s0' % (pithos.container, obj),
897
            ignore_content_type=False, content_type='application/json',
898
            metadata={'mkey2': 'mval2a', 'mkey3': 'mval3'},
899
            permissions={'write': ['u5', 'accX:groupB']})
900
        self.assertEqual(r.status_code, 201)
901
        self.info('Status code is OK')
902

    
903
        r = pithos.get_object_meta(obj + '0')
904
        self.assertEqual(r['x-object-meta-mkey1'], 'mval1')
905
        self.assertEqual(r['x-object-meta-mkey2'], 'mval2a')
906
        self.assertEqual(r['x-object-meta-mkey3'], 'mval3')
907
        self.info('Metadata are OK')
908

    
909
        r = pithos.get_object_sharing(obj + '0')
910
        self.assertFalse('read' in r)
911
        self.assertTrue('u5' in r['write'])
912
        self.assertTrue('accx:groupb' in r['write'])
913
        self.info('Sharing is OK')
914

    
915
        self.assertRaises(ClientError, pithos.get_object_info, obj)
916
        self.info('Old object is not there, which is OK')
917

    
918
        r = pithos.object_move(
919
            obj + '0',
920
            destination='/%s/%s' % (pithos.container, obj),
921
            content_encoding='utf8',
922
            content_type='application/json',
923
            destination_account='nonExistendAddress@NeverLand.com',
924
            success=(201, 404))
925
        self.assertEqual(r.status_code, 404)
926
        self.info('Non existing UUID correctly causes a 404')
927

    
928
        r = pithos.object_move(
929
            obj + '0',
930
            destination='/%s/%s' % (self.temp_containers[-2], obj),
931
            content_encoding='utf8',
932
            content_type='application/json',
933
            content_disposition='attachment; filename="fname.ext"')
934
        self.assertEqual(r.status_code, 201)
935
        self.assertEqual(
936
            r.headers['content-type'],
937
            'application/json; charset=UTF-8')
938

    
939
        pithos.container = self.temp_containers[-2]
940
        r = pithos.object_get(obj)
941
        etag = r.headers['etag']
942
        ctype = r.headers['content-type']
943
        self.assertEqual(ctype, 'application/json')
944
        self.assertTrue('fname.ext' in r.headers['content-disposition'])
945
        self.info('Cross container copy w. content-type/encoding is OK')
946

    
947
        r = pithos.object_move(
948
            obj,
949
            destination='/%s/%s0' % (pithos.container, obj),
950
            ignore_content_type=True,
951
            content_type='text/x-python')
952
        self.assertEqual(r.status_code, 201)
953
        self.assertNotEqual(r.headers['content-type'], 'application/json')
954
        r = pithos.object_get(obj + '0')
955
        self.assertNotEqual(r.headers['content-type'], 'text/x-python')
956

    
957
        r = pithos.object_move(
958
            obj + '0',
959
            destination='/%s/%s' % (pithos.container, obj),
960
            if_etag_match=etag)
961
        self.assertEqual(r.status_code, 201)
962
        self.info('if-etag-match is OK')
963

    
964
        r = pithos.object_move(
965
            obj,
966
            destination='/%s/%s0' % (pithos.container, obj),
967
            if_etag_not_match='lalala')
968
        self.assertEqual(r.status_code, 201)
969
        self.info('if-etag-not-match is OK')
970

    
971
        r = pithos.object_move(
972
            obj + '0',
973
            destination='/%s/%s' % (pithos.container, obj),
974
            format='xml',
975
            public=True)
976
        self.assertEqual(r.status_code, 201)
977
        self.assertTrue('xml' in r.headers['content-type'])
978

    
979
        r = pithos.get_object_info(obj)
980
        self.assertTrue('x-object-public' in r)
981
        self.info('Publish, format and source-version are OK')
982

    
983
    def test_070_object_post(self):
984
        """Test object POST"""
985
        pithos = self.clients.pithos
986
        obj = 'sample2post.file'
987
        newf = NamedTemporaryFile()
988
        newf.writelines([
989
            'ello!\n',
990
            'This is a test line\n',
991
            'inside a test file\n'])
992
        newf.flush()
993

    
994
        r = pithos.object_put(
995
            obj,
996
            content_type='text/x-python',
997
            data='H',
998
            metadata=dict(mkey1='mval1', mkey2='mval2'),
999
            permissions=dict(
1000
                read=['accX:groupA', 'u1', 'u2'],
1001
                write=['u2', 'u3']))
1002
        self.info(
1003
            'Prepared a local file %s & a remote object %s', newf.name, obj)
1004

    
1005
        newf.seek(0)
1006
        pithos.append_object(obj, newf)
1007
        r = pithos.object_get(obj)
1008
        self.assertEqual(r.text[:5], 'Hello')
1009
        self.info('Append is OK')
1010

    
1011
        newf.seek(0)
1012
        r = pithos.overwrite_object(obj, 0, 10, newf)
1013
        r = pithos.object_get(obj)
1014
        self.assertTrue(r.text.startswith('ello!'))
1015
        self.assertEqual(r.headers['content-type'], 'text/x-python')
1016
        self.info('Overwrite (involves content-legth/range/type) is OK')
1017

    
1018
        r = pithos.truncate_object(obj, 5)
1019
        r = pithos.object_get(obj)
1020
        self.assertEqual(r.text, 'ello!')
1021
        self.assertEqual(r.headers['content-type'], 'text/x-python')
1022
        self.info(
1023
            'Truncate (involves content-range, object-bytes and source-object)'
1024
            ' is OK')
1025

    
1026
        pithos.set_object_meta(obj, {'mkey2': 'mval2a', 'mkey3': 'mval3'})
1027
        r = pithos.get_object_meta(obj)
1028
        self.assertEqual(r['x-object-meta-mkey1'], 'mval1')
1029
        self.assertEqual(r['x-object-meta-mkey2'], 'mval2a')
1030
        self.assertEqual(r['x-object-meta-mkey3'], 'mval3')
1031
        pithos.del_object_meta(obj, 'mkey1')
1032
        r = pithos.get_object_meta(obj)
1033
        self.assertFalse('x-object-meta-mkey1' in r)
1034
        self.info('Metadata are OK')
1035

    
1036
        pithos.set_object_sharing(
1037
            obj, read_permission=['u4', 'u5'], write_permission=['u4'])
1038
        r = pithos.get_object_sharing(obj)
1039
        self.assertTrue('read' in r)
1040
        self.assertTrue('u5' in r['read'])
1041
        self.assertTrue('write' in r)
1042
        self.assertTrue('u4' in r['write'])
1043
        pithos.del_object_sharing(obj)
1044
        r = pithos.get_object_sharing(obj)
1045
        self.assertTrue(len(r) == 0)
1046
        self.info('Sharing is OK')
1047

    
1048
        pithos.publish_object(obj)
1049
        r = pithos.get_object_info(obj)
1050
        self.assertTrue('x-object-public' in r)
1051
        pithos.unpublish_object(obj)
1052
        r = pithos.get_object_info(obj)
1053
        self.assertFalse('x-object-public' in r)
1054
        self.info('Publishing is OK')
1055

    
1056
        etag = r['etag']
1057
        r = pithos.object_post(
1058
            obj,
1059
            update=True,
1060
            public=True,
1061
            if_etag_not_match=etag,
1062
            success=(412, 202, 204))
1063
        self.assertEqual(r.status_code, 412)
1064
        self.info('if-etag-not-match is OK')
1065

    
1066
        r = pithos.object_post(
1067
            obj,
1068
            update=True,
1069
            public=True,
1070
            if_etag_match=etag,
1071
            content_type='application/octet-srteam',
1072
            content_encoding='application/json')
1073

    
1074
        r = pithos.get_object_info(obj)
1075
        helloVersion = r['x-object-version']
1076
        self.assertTrue('x-object-public' in r)
1077
        self.assertEqual(r['content-type'], 'text/x-python')
1078
        self.info('If-etag-match is OK')
1079

    
1080
        pithos.container = self.temp_containers[-1]
1081
        pithos.create_object(obj)
1082
        r = pithos.object_post(
1083
            obj,
1084
            update=True,
1085
            content_type='application/octet-srteam',
1086
            content_length=5,
1087
            content_range='bytes 1-5/*',
1088
            source_object='/%s/%s' % (self.temp_containers[-2], obj),
1089
            source_account='thisAccountWillNeverExist@adminland.com',
1090
            source_version=helloVersion,
1091
            data='12345',
1092
            success=(416, 202, 204))
1093
        self.assertEqual(r.status_code, 416)
1094
        self.info('Successfully failed with invalid user UUID')
1095

    
1096
        pithos.upload_from_string(obj, '12345')
1097
        r = pithos.object_post(
1098
            obj,
1099
            update=True,
1100
            content_type='application/octet-srteam',
1101
            content_length=3,
1102
            content_range='bytes 1-3/*',
1103
            source_object='/%s/%s' % (self.temp_containers[-2], obj),
1104
            source_account=pithos.account,
1105
            source_version=helloVersion,
1106
            data='123',
1107
            content_disposition='attachment; filename="fname.ext"')
1108

    
1109
        r = pithos.object_get(obj)
1110
        self.assertEqual(r.text, '1ell5')
1111
        self.info('Cross container POST with source-version/account are OK')
1112

    
1113
        self.assertTrue('content-disposition' in r.headers)
1114
        self.assertTrue('fname.ext' in r.headers['content-disposition'])
1115
        self.info('Content-disposition POST is OK')
1116

    
1117
        mobj = 'manifest.test'
1118
        txt = ''
1119
        for i in range(10):
1120
            txt += '%s' % i
1121
            r = pithos.object_put(
1122
                '%s/%s' % (mobj, i),
1123
                data='%s' % i,
1124
                content_length=1,
1125
                success=201,
1126
                content_encoding='application/octet-stream',
1127
                content_type='application/octet-stream')
1128

    
1129
        pithos.create_object_by_manifestation(
1130
            mobj, content_type='application/octet-stream')
1131

    
1132
        r = pithos.object_post(
1133
            mobj, manifest='%s/%s' % (pithos.container, mobj))
1134

    
1135
        r = pithos.object_get(mobj)
1136
        self.assertEqual(r.text, txt)
1137
        self.info('Manifestation is OK')
1138

    
1139
        """We need to check transfer_encoding """
1140

    
1141
    def test_075_object_delete(self):
1142
        """Test object DELETE"""
1143
        pithos = self.clients.pithos
1144
        obj = 'sample2post.file'
1145

    
1146
        r = pithos.object_delete(obj, until=1000000)
1147
        r = pithos.object_get(obj, success=(200, 404))
1148
        self.assertEqual(r.status_code, 200)
1149
        self.info('Successfully failed to delete with false "until"')
1150

    
1151
        r = pithos.object_delete(obj)
1152
        self.assertEqual(r.status_code, 204)
1153
        self.info('Status code is OK')
1154

    
1155
        r = pithos.object_get(obj, success=(200, 404))
1156
        self.assertEqual(r.status_code, 404)
1157
        self.info('Successfully failed to delete a deleted file')
1158

    
1159
    @classmethod
1160
    def tearDownClass(cls):  # noqa
1161
        """Clean up"""
1162
        from kamaki.cli.logger import deactivate
1163
        deactivate('kamaki.clients.send')
1164
        deactivate('kamaki.clients.recv')
1165
        pithos = cls.clients.pithos
1166
        for c in getattr(cls, 'temp_containers', []):
1167
            pithos.container = c
1168
            try:
1169
                pithos.del_container(delimiter='/')
1170
                pithos.purge_container(c)
1171
            except ClientError as ce:
1172
                print ('Failed to destroy container (%s)' % ce)