Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (33.8 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.assertEqual(source_hashmap, target_hashmap)
742
        self.info('Source-version is OK')
743

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

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

    
770
        """MISSING: test transfer-encoding?"""
771

    
772
    def test_060_object_copy(self):
773
        pithos = self.clients.pithos
774
        obj, trg = 'source.file2copy', 'copied.file'
775
        data = '{"key1":"val1", "key2":"val2"}'
776

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

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

    
797
        r = pithos.get_object_info(trg)
798
        self.assertTrue('content-disposition' in r)
799
        self.info('Content-disposition is OK')
800

    
801
        self.assertEqual(r['x-object-meta-mkey1'], 'mval1')
802
        self.assertEqual(r['x-object-meta-mkey2'], 'mval2a')
803
        self.assertEqual(r['x-object-meta-mkey3'], 'mval3')
804
        self.info('Metadata are OK')
805

    
806
        r = pithos.get_object_sharing(trg)
807
        self.assertFalse('read' in r or 'u2' in r['write'])
808
        self.assertTrue('accx:groupb' in r['write'])
809
        self.info('Sharing is OK')
810

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

    
821
        """Check destination being another container
822
        and also content_type and content encoding"""
823
        r = pithos.object_copy(
824
            obj,
825
            destination='/%s/%s' % (self.temp_containers[-1], obj),
826
            content_encoding='utf8',
827
            content_type='application/json')
828
        self.assertEqual(r.status_code, 201)
829
        self.assertEqual(
830
            r.headers['content-type'],
831
            'application/json; charset=UTF-8')
832

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

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

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

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

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

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

    
877
    @classmethod
878
    def tearDownClass(cls):  # noqa
879
        """Clean up"""
880
        from kamaki.cli.logger import deactivate
881
        deactivate('kamaki.clients.send')
882
        deactivate('kamaki.clients.recv')
883
        pithos = cls.clients.pithos
884
        for c in getattr(cls, 'temp_containers', []):
885
            pithos.container = c
886
            try:
887
                pithos.del_container(delimiter='/')
888
                pithos.purge_container(c)
889
            except ClientError as ce:
890
                print ('Failed to destroy container (%s)' % ce)