Revision 33ffca25 pithos/api/tests.py

b/pithos/api/tests.py
71 71
                'Content-Type',
72 72
                'Last-Modified',
73 73
                'Content-Length',
74
                'Date',),
74
                'Date',
75
                'X-Container-Block-Size',
76
                'X-Container-Block-Hash',),
75 77
            'object':(
76 78
                'ETag',
77 79
                'Content-Length',
......
132 134
        self.assert_headers(response, 'account', exp_meta)
133 135
        return response
134 136

  
135
    def list_containers(self, account, limit=10000, marker='', format='', **headers):
137
    def list_containers(self, account, limit=10000, marker='', format='',
138
                        **headers):
136 139
        params = locals()
137 140
        params.pop('self')
138 141
        params.pop('account')
......
167 170
            self.assert_headers(response, 'container', exp_meta)
168 171
        return response
169 172

  
170
    def list_objects(self, account, container, limit=10000, marker='', prefix='', format='', path='', delimiter='', meta='', **headers):
173
    def list_objects(self, account, container, limit=10000, marker='',
174
                     prefix='', format='', path='', delimiter='', meta='',
175
                     **headers):
171 176
        params = locals()
172 177
        params.pop('self')
173 178
        params.pop('account')
......
189 194

  
190 195
    def update_container_meta(self, account, name, **meta):
191 196
        path = '/v1/%s/%s' %(account, name)
192
        response = self.client.post(path, data={}, content_type='text/xml', follow=False, **meta)
197
        response = self.client.post(path,
198
                                    data=None,
199
                                    content_type='text/xml',
200
                                    follow=False, **meta)
193 201
        response.content = response.content.strip()
194 202
        self.assert_status(response, 202)
195 203
        return response
......
217 225
            self.assert_headers(response, 'object')
218 226
        return response
219 227

  
220
    def upload_object(self, account, container, name, data, content_type='application/json', **headers):
228
    def upload_object(self, account, container, name, data, content_type='',
229
                      **headers):
221 230
        path = '/v1/%s/%s/%s' %(account, container, name)
222 231
        response = self.client.put(path, data, content_type, **headers)
223 232
        response.content = response.content.strip()
......
242 251
        self.assert_status(response, 201)
243 252
        return response
244 253

  
245
    def update_object_meta(self, account, container, name, **headers):
254
    def update_object(self, account, container, name, data={},
255
                      content_type='MULTIPART_CONTENT', **headers):
246 256
        path = '/v1/%s/%s/%s' %(account, container, name)
247
        response = self.client.post(path, **headers)
257
        response = self.client.post(path, data, content_type, **headers)
248 258
        response.content = response.content.strip()
249
        self.assert_status(response, 202)
259
        self.assert_status(response, [202, 204, 416])
250 260
        return response
251 261

  
252 262
    def delete_object(self, account, container, name):
......
260 270
        entities = ['Account', 'Container', 'Container-Object', 'Object']
261 271
        user_defined_meta = ['X-%s-Meta' %elem for elem in entities]
262 272
        headers = [item for item in response._headers.values()]
263
        system_headers = [h for h in headers if not h[0].startswith(tuple(user_defined_meta))]
273
        t = tuple(user_defined_meta)
274
        system_headers = [h for h in headers if not h[0].startswith(t)]
264 275
        for h in system_headers:
265 276
            self.assertTrue(h[0] in self.headers[type])
266 277
            if exp_meta:
267 278
                self.assertEqual(h[1], exp_meta[h[0]])
268 279

  
269 280
    def assert_extended(self, response, format, type, size):
270
        self.assertEqual(response['Content-Type'].find(self.contentTypes[format]), 0)
281
        exp_content_type = self.contentTypes[format]
282
        self.assertEqual(response['Content-Type'].find(exp_content_type), 0)
271 283
        if format == 'xml':
272 284
            self.assert_xml(response, type, size)
273 285
        elif format == 'json':
......
307 319
        except IOError:
308 320
            return
309 321

  
310
    def upload_random_data(self, account, container, name, length=1024, meta={}):
311
        char_set = string.ascii_uppercase + string.digits
312
        data = ''.join(random.choice(char_set) for x in range(length))
322
    def upload_random_data(self, account, container, name, length=1024,
323
                           meta={}):
324
        data = get_random_data(length)
313 325
        return self.upload_data(account, container, name, data, meta)
314 326

  
315 327
    def upload_data(self, account, container, name, data, meta={}):
......
320 332
            obj['hash'] = compute_md5_hash(obj['data'])
321 333
            meta.update({'HTTP_X_OBJECT_META_TEST':'test1',
322 334
                         'HTTP_ETAG':obj['hash']})
323
            meta['HTTP_CONTENT_TYPE'], enc = mimetypes.guess_type(name)
335
            type, enc = mimetypes.guess_type(name)
336
            meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text'
324 337
            if enc:
325
                meta['HTTP_CONTENT_TYPE'] = enc
338
                meta['HTTP_CONTENT_ENCODING'] = enc
339
            
326 340
            obj['meta'] = meta
327 341
            r = self.upload_object(account,
328 342
                               container,
......
351 365
        response = self.get_account_meta(self.account)
352 366
        r2 = self.list_containers(self.account)
353 367
        containers =  get_content_splitted(r2)
354
        self.assertEqual(response['X-Account-Container-Count'], str(len(containers)))
368
        l = str(len(containers))
369
        self.assertEqual(response['X-Account-Container-Count'], l)
355 370
        size = 0
356 371
        for c in containers:
357 372
            r = self.get_container_meta(self.account, c)
......
394 409
        self.assertEquals(self.containers[:2], containers)
395 410

  
396 411
    def test_list_with_marker(self):
397
        limit = 2
398
        marker = 'bananas'
399
        response = self.list_containers(self.account, limit=limit, marker=marker)
412
        l = 2
413
        m = 'bananas'
414
        response = self.list_containers(self.account, limit=l, marker=m)
400 415
        containers =  get_content_splitted(response)
401
        i = self.containers.index(marker) + 1
402
        self.assertEquals(self.containers[i:(i+limit)], containers)
416
        i = self.containers.index(m) + 1
417
        self.assertEquals(self.containers[i:(i+l)], containers)
403 418
        
404
        marker = 'oranges'
405
        response = self.list_containers(self.account, limit=limit, marker=marker)
419
        m = 'oranges'
420
        response = self.list_containers(self.account, limit=l, marker=m)
406 421
        containers = get_content_splitted(response)
407
        i = self.containers.index(marker) + 1
408
        self.assertEquals(self.containers[i:(i+limit)], containers)
422
        i = self.containers.index(m) + 1
423
        self.assertEquals(self.containers[i:(i+l)], containers)
409 424

  
410 425
    #def test_extended_list(self):
411 426
    #    self.list_containers(self.account, limit=3, format='xml')
412 427
    #    self.list_containers(self.account, limit=3, format='json')
413 428

  
414 429
    def test_list_json_with_marker(self):
415
        limit = 2
416
        marker = 'bananas'
417
        response = self.list_containers(self.account, limit=limit, marker=marker, format='json')
430
        l = 2
431
        m = 'bananas'
432
        response = self.list_containers(self.account, limit=l, marker=m,
433
                                        format='json')
418 434
        containers = json.loads(response.content)
419 435
        self.assertEqual(containers[0]['name'], 'kiwis')
420 436
        self.assertEqual(containers[1]['name'], 'oranges')
421 437

  
422 438
    def test_list_xml_with_marker(self):
423
        limit = 2
424
        marker = 'oranges'
425
        response = self.list_containers(self.account, limit=limit, marker=marker, format='xml')
439
        l = 2
440
        m = 'oranges'
441
        response = self.list_containers(self.account, limit=l, marker=m,
442
                                        format='xml')
426 443
        xml = minidom.parseString(response.content)
427 444
        nodes = xml.getElementsByTagName('name')
428 445
        self.assertEqual(len(nodes), 1)
......
505 522
            self.delete_container(self.account, c)
506 523

  
507 524
    def test_update_meta(self):
508
        meta = {'HTTP_X_ACCOUNT_META_TEST':'test', 'HTTP_X_ACCOUNT_META_TOST':'tost'}
525
        meta = {'HTTP_X_ACCOUNT_META_TEST':'test',
526
                'HTTP_X_ACCOUNT_META_TOST':'tost'}
509 527
        response = self.update_account_meta(self.account, **meta)
510 528
        response = self.get_account_meta(self.account)
511 529
        for k,v in meta.items():
......
515 533

  
516 534
    #def test_invalid_account_update_meta(self):
517 535
    #    with AssertInvariant(self.get_account_meta, self.account):
518
    #        meta = {'HTTP_X_ACCOUNT_META_TEST':'test', 'HTTP_X_ACCOUNT_META_TOST':'tost'}
536
    #        meta = {'HTTP_X_ACCOUNT_META_TEST':'test',
537
    #               'HTTP_X_ACCOUNT_META_TOST':'tost'}
519 538
    #        response = self.update_account_meta('non-existing-account', **meta)
520 539

  
521 540
class ContainerHead(BaseTestCase):
......
590 609
                   'moms_birthday.jpg']
591 610
        limit = 4
592 611
        for m in markers:
593
            response = self.list_objects(self.account, self.container[0], limit=limit, marker=m)
612
            response = self.list_objects(self.account, self.container[0],
613
                                         limit=limit, marker=m)
594 614
            objects = get_content_splitted(response)
595 615
            l = [elem['name'] for elem in self.obj[:8]]
596 616
            l.sort()
......
600 620
            self.assertEqual(objects, l[start:end])
601 621

  
602 622
    def test_list_pseudo_hierarchical_folders(self):
603
        response = self.list_objects(self.account, self.container[1], prefix='photos', delimiter='/')
623
        response = self.list_objects(self.account, self.container[1],
624
                                     prefix='photos', delimiter='/')
604 625
        objects = get_content_splitted(response)
605
        self.assertEquals(['photos/animals/', 'photos/me.jpg', 'photos/plants/'], objects)
626
        self.assertEquals(['photos/animals/', 'photos/me.jpg',
627
                           'photos/plants/'], objects)
606 628
        
607
        response = self.list_objects(self.account, self.container[1], prefix='photos/animals', delimiter='/')
608
        objects = get_content_splitted(response)
609
        self.assertEquals(['photos/animals/cats/', 'photos/animals/dogs/'], objects)
629
        response = self.list_objects(self.account, self.container[1],
630
                                     prefix='photos/animals', delimiter='/')
631
        objs = get_content_splitted(response)
632
        l = ['photos/animals/cats/', 'photos/animals/dogs/']
633
        self.assertEquals(l, objs)
610 634
        
611
        response = self.list_objects(self.account, self.container[1], path='photos')
635
        response = self.list_objects(self.account, self.container[1],
636
                                     path='photos')
612 637
        objects = get_content_splitted(response)
613 638
        self.assertEquals(['photos/me.jpg'], objects)
614 639

  
615 640
    def test_extended_list_json(self):
616
        response = self.list_objects(self.account, self.container[1], format='json', limit=2, prefix='photos/animals', delimiter='/')
641
        response = self.list_objects(self.account,
642
                                     self.container[1],
643
                                     format='json', limit=2,
644
                                     prefix='photos/animals',
645
                                     delimiter='/')
617 646
        objects = json.loads(response.content)
618 647
        self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
619 648
        self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
620 649

  
621 650
    def test_extended_list_xml(self):
622
        response = self.list_objects(self.account, self.container[1], format='xml', limit=4, prefix='photos', delimiter='/')
651
        response = self.list_objects(self.account, self.container[1],
652
                                     format='xml', limit=4, prefix='photos',
653
                                     delimiter='/')
623 654
        xml = minidom.parseString(response.content)
624 655
        dirs = xml.getElementsByTagName('subdir')
625 656
        self.assertEqual(len(dirs), 2)
......
633 664
    def test_list_using_meta(self):
634 665
        meta = {'HTTP_X_OBJECT_META_QUALITY':'aaa'}
635 666
        for o in self.obj[:2]:
636
            r = self.update_object_meta(self.account,
667
            r = self.update_object(self.account,
637 668
                                    self.container[0],
638 669
                                    o['name'],
639 670
                                    **meta)
640 671
        meta = {'HTTP_X_OBJECT_META_STOCK':'true'}
641 672
        for o in self.obj[3:5]:
642
            r = self.update_object_meta(self.account,
673
            r = self.update_object(self.account,
643 674
                                    self.container[0],
644 675
                                    o['name'],
645 676
                                    **meta)
......
729 760
        
730 761
            #assert success
731 762
            self.assertEqual(r.status_code, 200)
763
            objlist = self.list_objects(self.account, self.container[0])
732 764
            self.assertEqual(get_content_splitted(r),
733
                             get_content_splitted(self.list_objects(self.account,
734
                                                                    self.container[0])))
765
                             get_content_splitted(objlist))
735 766

  
736 767
    def test_if_unmodified_since_precondition_failed(self):
737 768
        t = datetime.datetime.utcnow()
......
765 796
        response = self.create_container(self.account, self.containers[0])
766 797
        if response.status_code == 201:
767 798
            response = self.list_containers(self.account)
768
            self.assertTrue(self.containers[0] in get_content_splitted(response))
799
            content = get_content_splitted(response)
800
            self.assertTrue(self.containers[0] in content)
769 801
            r = self.get_container_meta(self.account, self.containers[0])
770 802
            self.assertEqual(r.status_code, 204)
771 803

  
772 804
    def test_create_twice(self):
773 805
        response = self.create_container(self.account, self.containers[0])
774 806
        if response.status_code == 201:
775
            self.assertTrue(self.create_container(self.account, self.containers[0]).status_code, 202)
807
            r = self.create_container(self.account, self.containers[0])
808
            self.assertTrue(r.status_code, 202)
776 809

  
777 810
class ContainerPost(BaseTestCase):
778 811
    def setUp(self):
......
789 822
    def test_update_meta(self):
790 823
        meta = {'HTTP_X_CONTAINER_META_TEST':'test33',
791 824
                'HTTP_X_CONTAINER_META_TOST':'tost22'}
792
        response = self.update_container_meta(self.account, self.container, **meta)
825
        response = self.update_container_meta(self.account, self.container,
826
                                              **meta)
793 827
        response = self.get_container_meta(self.account, self.container)
794 828
        for k,v in meta.items():
795 829
            key = '-'.join(elem.capitalize() for elem in k.split('_')[1:])
......
859 893
                            self.objects[0]['meta'])
860 894
        #assert success
861 895
        self.assertEqual(r.status_code, 200)
896
        
897
        #assert content-type
898
        self.assertEqual(r['Content-Type'],
899
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
862 900

  
863 901
    def test_get_invalid(self):
864 902
        r = self.get_object(self.account,
......
877 915
        #assert successful partial content
878 916
        self.assertEqual(r.status_code, 206)
879 917
        
918
        #assert content-type
919
        self.assertEqual(r['Content-Type'],
920
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
921
        
880 922
        #assert content length
881 923
        self.assertEqual(int(r['Content-Length']), 500)
882 924
        
......
894 936
        #assert successful partial content
895 937
        self.assertEqual(r.status_code, 206)
896 938
        
939
        #assert content-type
940
        self.assertEqual(r['Content-Type'],
941
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
942
        
897 943
        #assert content length
898 944
        self.assertEqual(int(r['Content-Length']), 500)
899 945
        
......
912 958
        #assert successful partial content
913 959
        self.assertEqual(r.status_code, 206)
914 960
        
961
        #assert content-type
962
        self.assertEqual(r['Content-Type'],
963
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
964
        
915 965
        #assert content length
916 966
        self.assertEqual(int(r['Content-Length']), 500)
917 967
        
......
1002 1052
        #assert get success
1003 1053
        self.assertEqual(r.status_code, 200)
1004 1054
        
1055
        #assert content-type
1056
        self.assertEqual(r['Content-Type'],
1057
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1058
        
1005 1059
        #assert response content
1006 1060
        self.assertEqual(self.objects[0]['data'].strip(), r.content.strip())
1007 1061

  
......
1015 1069
        #assert get success
1016 1070
        self.assertEqual(r.status_code, 200)
1017 1071
        
1072
        #assert content-type
1073
        self.assertEqual(r['Content-Type'],
1074
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1075
        
1018 1076
        #assert response content
1019 1077
        self.assertEqual(self.objects[0]['data'].strip(), r.content.strip())
1020 1078

  
......
1030 1088
        #assert get success
1031 1089
        self.assertEqual(r.status_code, 200)
1032 1090
        
1091
        #assert content-type
1092
        self.assertEqual(r['Content-Type'],
1093
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1094
        
1095
        #assert content-type
1096
        self.assertEqual(r['Content-Type'],
1097
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1098
        
1033 1099
        #assert response content
1034 1100
        self.assertEqual(self.objects[0]['data'].strip(), r.content.strip())
1035 1101

  
......
1053 1119
        
1054 1120
        #assert get success
1055 1121
        self.assertEqual(r.status_code, 200)
1122
        
1123
        #assert content-type
1124
        self.assertEqual(r['Content-Type'],
1125
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1056 1126

  
1057 1127
    def test_if_none_match(self):
1058 1128
        #perform get with If-None-Match *
......
1098 1168
            
1099 1169
            #assert get success
1100 1170
            self.assertEqual(r.status_code, 200)
1171
            
1172
            #assert content-type
1173
            self.assertEqual(r['Content-Type'],
1174
                             self.objects[0]['meta']['HTTP_CONTENT_TYPE'])   
1101 1175

  
1102 1176
    def test_if_modified_since_invalid_date(self):
1103 1177
        headers = {'HTTP_IF_MODIFIED_SINCE':''}
......
1108 1182
        
1109 1183
        #assert get success
1110 1184
        self.assertEqual(r.status_code, 200)
1185
        
1186
        #assert content-type
1187
        self.assertEqual(r['Content-Type'],
1188
                         self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1111 1189

  
1112 1190
    def test_if_not_modified_since(self):
1113 1191
        now = datetime.datetime.utcnow()
......
1136 1214
            #assert success
1137 1215
            self.assertEqual(r.status_code, 200)
1138 1216
            self.assertEqual(self.objects[0]['data'], r.content)
1217
            
1218
            #assert content-type
1219
            self.assertEqual(r['Content-Type'],
1220
                             self.objects[0]['meta']['HTTP_CONTENT_TYPE'])
1139 1221

  
1140 1222
    def test_if_unmodified_since_precondition_failed(self):
1141 1223
        t = datetime.datetime.utcnow()
......
1159 1241
            self.assertEqual(r.status_code, 412)
1160 1242

  
1161 1243
    def test_hashes(self):
1162
        #block_size = 4 * 1024 * 1024
1163
        block_size = 128 * 1024
1164
        block_num = 2
1165
        l = block_size * block_num + 1
1166
        fname = 'largefile.txt'
1244
        l = 8388609
1245
        fname = 'largefile'
1167 1246
        o = self.upload_random_data(self.account,
1168 1247
                                self.containers[1],
1169 1248
                                fname,
......
1173 1252
                                self.containers[1],
1174 1253
                                fname,
1175 1254
                                'json')
1176
            hashes = json.loads(r.content)['hashes']
1177
            self.assertTrue(len(hashes), block_num + 1)
1255
            body = json.loads(r.content)
1256
            hashes = body['hashes']
1257
            block_size = body['block_size']
1258
            block_hash = body['block_hash']
1259
            block_num = l/block_size == 0 and l/block_size or l/block_size + 1
1260
            self.assertTrue(len(hashes), block_num)
1178 1261
            i = 0
1179 1262
            for h in hashes:
1180 1263
                start = i * block_size
1181 1264
                end = (i + 1) * block_size
1182
                self.assertEqual(h, compute_block_hash(o['data'][start:end]))
1265
                hash = compute_block_hash(o['data'][start:end], block_hash)
1266
                self.assertEqual(h, hash)
1183 1267
                i += 1
1184 1268

  
1185 1269
class ObjectPut(BaseTestCase):
......
1194 1278
        create_chunked_update_test_file(self.src, self.dest)
1195 1279

  
1196 1280
    def tearDown(self):
1197
        for o in get_content_splitted(self.list_objects(self.account, self.container)):
1281
        r = self.list_objects(self.account, self.container)
1282
        for o in get_content_splitted(r):
1198 1283
            self.delete_object(self.account, self.container, o)
1199 1284
        self.delete_container(self.account, self.container)
1200 1285
        
......
1211 1296
              'HTTP_X_OBJECT_MANIFEST':123,
1212 1297
              'HTTP_X_OBJECT_META_TEST':'test1'
1213 1298
              }
1214
        meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(fullpath)
1299
        type, enc = mimetypes.guess_type(fullpath)
1300
        meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text'
1301
        if enc:
1302
            meta['HTTP_CONTENT_ENCODING'] = enc
1215 1303
        r = self.upload_object(self.account,
1216 1304
                               self.container,
1217 1305
                               filename,
......
1221 1309
        self.assertEqual(r.status_code, 201)
1222 1310
        r = self.get_object_meta(self.account, self.container, filename)
1223 1311
        self.assertTrue(r['X-Object-Meta-Test'])
1224
        self.assertEqual(r['X-Object-Meta-Test'], meta['HTTP_X_OBJECT_META_TEST'])
1312
        self.assertEqual(r['X-Object-Meta-Test'],
1313
                         meta['HTTP_X_OBJECT_META_TEST'])
1225 1314
        
1226 1315
        #assert uploaded content
1227 1316
        r = self.get_object(self.account, self.container, filename)
......
1237 1326
              'HTTP_X_OBJECT_MANIFEST':123,
1238 1327
              'HTTP_X_OBJECT_META_TEST':'test1'
1239 1328
              }
1240
        meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(fullpath)
1329
        type, enc = mimetypes.guess_type(fullpath)
1330
        meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text'
1331
        if enc:
1332
            meta['HTTP_CONTENT_ENCODING'] = enc
1241 1333
        r = self.upload_object(self.account,
1242 1334
                               self.container,
1243 1335
                               filename,
......
1251 1343
        f = open(self.dest, 'r')
1252 1344
        data = f.read()
1253 1345
        meta = {}
1254
        meta['HTTP_CONTENT_TYPE'], meta['HTTP_CONTENT_ENCODING'] = mimetypes.guess_type(objname)
1346
        type, enc = mimetypes.guess_type(self.dest)
1347
        meta['HTTP_CONTENT_TYPE'] = type and type or 'plain/text'
1348
        if enc:
1349
            meta['HTTP_CONTENT_ENCODING'] = enc
1255 1350
        meta.update({'HTTP_TRANSFER_ENCODING':'chunked'})
1256 1351
        r = self.upload_object(self.account,
1257 1352
                               self.container,
......
1287 1382
            self.delete_container(self.account, c)
1288 1383

  
1289 1384
    def test_copy(self):
1290
        with AssertInvariant(self.get_object_meta, self.account, self.containers[0], self.obj['name']):
1385
        with AssertInvariant(self.get_object_meta, self.account,
1386
                             self.containers[0], self.obj['name']):
1291 1387
            #perform copy
1292 1388
            meta = {'HTTP_X_OBJECT_META_TEST':'testcopy'}
1293 1389
            src_path = os.path.join('/', self.containers[0], self.obj['name'])
......
1310 1406
            self.assertEqual(r['ETag'], self.obj['hash'])
1311 1407
            
1312 1408
            #assert src object still exists
1313
            r = self.get_object_meta(self.account, self.containers[0], self.obj['name'])
1409
            r = self.get_object_meta(self.account, self.containers[0],
1410
                                     self.obj['name'])
1314 1411
            self.assertEqual(r.status_code, 204)
1315 1412

  
1316 1413
    def test_copy_from_different_container(self):
......
1335 1432
            self.assertTrue(r['X-Object-Meta-Test'], 'testcopy')
1336 1433
            
1337 1434
            #assert src object still exists
1338
            r = self.get_object_meta(self.account, self.containers[0], self.obj['name'])
1435
            r = self.get_object_meta(self.account, self.containers[0],
1436
                                     self.obj['name'])
1339 1437
            self.assertEqual(r.status_code, 204)
1340 1438

  
1341 1439
    def test_copy_invalid(self):
......
1379 1477
        self.assertTrue(r['X-Object-Meta-Test'], 'testcopy')
1380 1478
        
1381 1479
        #assert src object no more exists
1382
        r = self.get_object_meta(self.account, self.containers[0], self.obj['name'])
1480
        r = self.get_object_meta(self.account, self.containers[0],
1481
                                 self.obj['name'])
1383 1482
        self.assertItemNotFound(r)
1384 1483

  
1385 1484
class ObjectPost(BaseTestCase):
......
1399 1498
                self.delete_object(self.account, c, o)
1400 1499
            self.delete_container(self.account, c)
1401 1500

  
1402
    def test_update(self):
1501
    def test_update_meta(self):
1403 1502
        #perform update metadata
1404 1503
        more = {'HTTP_X_OBJECT_META_FOO':'foo',
1405 1504
                'HTTP_X_OBJECT_META_BAR':'bar'}
1406
        r = self.update_object_meta(self.account,
1505
        r = self.update_object(self.account,
1407 1506
                                self.containers[0],
1408 1507
                                self.obj['name'],
1409 1508
                                **more)
......
1411 1510
        self.assertEqual(r.status_code, 202)
1412 1511
        
1413 1512
        #assert old metadata are still there
1414
        r = self.get_object_meta(self.account, self.containers[0], self.obj['name'])
1513
        r = self.get_object_meta(self.account, self.containers[0],
1514
                                 self.obj['name'])
1415 1515
        self.assertTrue('X-Object-Meta-Test' not in r.items())
1416 1516
        
1417 1517
        #assert new metadata have been updated
......
1420 1520
            self.assertTrue(r[key])
1421 1521
            self.assertTrue(r[key], v)
1422 1522

  
1523
    def test_update_object(self,
1524
                           first_byte_pos=0,
1525
                           last_byte_pos=499,
1526
                           instance_length = True,
1527
                           content_length = 500):
1528
        l = len(self.obj['data'])
1529
        if instance_length:
1530
            range = 'bytes %d-%d/%d' %(first_byte_pos,
1531
                                       last_byte_pos,
1532
                                       l)
1533
        else:
1534
            range = 'bytes %d-%d/*' %(first_byte_pos,
1535
                                       last_byte_pos)
1536
        partial = last_byte_pos - first_byte_pos + 1
1537
        data = get_random_data(partial)
1538
        more = {'HTTP_CONTENT_RANGE':range}
1539
        if content_length:
1540
            more.update({'CONTENT_LENGTH':'%s' % content_length})
1541
        
1542
        r = self.update_object(self.account,
1543
                                self.containers[0],
1544
                                self.obj['name'],
1545
                                data,
1546
                                'application/octet-stream',
1547
                                **more)
1548
        
1549
        if partial < 0 or (instance_length and l <= last_byte_pos):
1550
            self.assertEqual(r.status_code, 202)    
1551
        elif content_length and content_length != partial:
1552
            self.assertEqual(r.status_code, 400)
1553
        else:
1554
            self.assertEqual(r.status_code, 204)
1555
            
1556
            #check modified object
1557
            r = self.get_object(self.account,
1558
                            self.containers[0],
1559
                            self.obj['name'])
1560
            self.assertEqual(r.content[0:partial], data)
1561
            self.assertEqual(r.content[partial:l], self.obj['data'][partial:l])
1562

  
1563
    def test_update_object_no_content_length(self):
1564
        self.test_update_object(content_length = None)
1565

  
1566
    def test_update_object_invalid_content_length(self):
1567
        with AssertContentInvariant(self.get_object, self.account, self.containers[0],
1568
                            self.obj['name']):
1569
            self.test_update_object(content_length = 1000)
1570

  
1571
    def test_update_object_with_unknown_instance_length(self):
1572
        self.test_update_object(instance_length = False)
1573

  
1574
    def test_update_object_invalid_range(self):
1575
        with AssertContentInvariant(self.get_object, self.account, self.containers[0],
1576
                            self.obj['name']):
1577
            self.test_update_object(499, 0, True)
1578
    
1579
    def test_update_object_invalid_range_and_length(self):
1580
        with AssertContentInvariant(self.get_object, self.account, self.containers[0],
1581
                            self.obj['name']):
1582
            self.test_update_object(499, 0, True, -1)
1583
    
1584
    def test_update_object_invalid_range_with_no_content_length(self):
1585
        with AssertContentInvariant(self.get_object, self.account, self.containers[0],
1586
                            self.obj['name']):
1587
            self.test_update_object(499, 0, True, content_length = None)
1588
    
1589
    def test_update_object_out_of_limits(self):    
1590
        with AssertContentInvariant(self.get_object, self.account, self.containers[0],
1591
                            self.obj['name']):
1592
            l = len(self.obj['data'])
1593
            self.test_update_object(0, l+1, True)
1594

  
1595
    def test_append(self):
1596
        data = get_random_data(500)
1597
        more = {'CONTENT_LENGTH':'500',
1598
                'HTTP_CONTENT_RANGE':'bytes */*'}
1599
        
1600
        r = self.update_object(self.account,
1601
                                self.containers[0],
1602
                                self.obj['name'],
1603
                                data,
1604
                                'application/octet-stream',
1605
                                **more)
1606
        
1607
        self.assertEqual(r.status_code, 204)
1608
        
1609
        r = self.get_object(self.account,
1610
                                self.containers[0],
1611
                                self.obj['name'])
1612
        self.assertEqual(len(r.content), len(self.obj['data']) + 500)
1613

  
1614
    #def test_update_with_chunked_transfer(self):
1615
    #    linenum = 5
1616
    #    data = create_random_chunked_data(linenum)
1617
    #    print data
1618
    #    first_byte_pos=0,
1619
    #    last_byte_pos=499,
1620
    #    instance_length = True,
1621
    #    content_length = 500
1622
    #    l = len(self.obj['data'])
1623
    #    meta = {'HTTP_TRANSFER_ENCODING':'chunked',
1624
    #            'HTTP_CONTENT_RANGE':'bytes 0-499/%d' %l}
1625
    #    r = self.update_object(self.account,
1626
    #                            self.containers[0],
1627
    #                            self.obj['name'],
1628
    #                            data,
1629
    #                            'application/octet-stream',
1630
    #                            **meta)
1631
    #    print r.request, r.status_code, r
1632

  
1423 1633
class ObjectDelete(BaseTestCase):
1424 1634
    def setUp(self):
1425 1635
        BaseTestCase.setUp(self)
......
1439 1649

  
1440 1650
    def test_delete(self):
1441 1651
        #perform delete object
1442
        r = self.delete_object(self.account, self.containers[0], self.obj['name'])
1652
        r = self.delete_object(self.account, self.containers[0],
1653
                               self.obj['name'])
1443 1654
        
1444 1655
        #assert success
1445 1656
        self.assertEqual(r.status_code, 204)
1446 1657

  
1447 1658
    def test_delete_invalid(self):
1448 1659
        #perform delete object
1449
        r = self.delete_object(self.account, self.containers[1], self.obj['name'])
1660
        r = self.delete_object(self.account, self.containers[1],
1661
                               self.obj['name'])
1450 1662
        
1451 1663
        #assert failure
1452 1664
        self.assertItemNotFound(r)
......
1465 1677
        items = self.callable(*self.args, **self.kwargs).items()
1466 1678
        assert self.items == items
1467 1679

  
1680
class AssertContentInvariant(object):
1681
    def __init__(self, callable, *args, **kwargs):
1682
        self.callable = callable
1683
        self.args = args
1684
        self.kwargs = kwargs
1685

  
1686
    def __enter__(self):
1687
        self.content = self.callable(*self.args, **self.kwargs).content
1688
        return self.content
1689

  
1690
    def __exit__(self, type, value, tb):
1691
        content = self.callable(*self.args, **self.kwargs).content
1692
        assert self.content == content
1693

  
1468 1694
def get_content_splitted(response):
1469 1695
    if response:
1470 1696
        return response.content.split('\n')
......
1475 1701
    md5.update(data)
1476 1702
    return md5.hexdigest().lower()
1477 1703

  
1478
def compute_block_hash(data):
1479
    h = hashlib.new(backend.hash_algorithm)
1704
def compute_block_hash(data, algorithm):
1705
    h = hashlib.new(algorithm)
1480 1706
    h.update(data.rstrip('\x00'))
1481 1707
    return h.hexdigest()
1482 1708

  
......
1492 1718
    fw.write(hex(0))
1493 1719
    fw.write('\r\n')
1494 1720

  
1721
def create_random_chunked_data(rows):
1722
    i = 0
1723
    out = []
1724
    while i < rows:
1725
        data = get_random_data(random.randint(1, 100))
1726
        out.append(hex(len(data)))
1727
        out.append(data)
1728
        i+=1
1729
    out.append(hex(0))
1730
    out.append('\r\n')
1731
    return '\r\n'.join(out)
1732

  
1733
def get_random_data(length):
1734
    char_set = string.ascii_uppercase + string.digits
1735
    return ''.join(random.choice(char_set) for x in range(length))
1736

  
1495 1737
o_names = ['kate.jpg',
1496 1738
           'kate_beckinsale.jpg',
1497 1739
           'How To Win Friends And Influence People.pdf',

Also available in: Unified diff