1 # Copyright 2013 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
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.
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.
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.
34 from unittest import TestCase
35 from mock import patch, call
36 from tempfile import NamedTemporaryFile
37 from os import urandom
38 from itertools import product
39 from random import randint
42 from collections import OrderedDict
44 from kamaki.clients.commisioning.utils.ordereddict import OrderedDict
46 from kamaki.clients import ClientError
47 from kamaki.clients.pithos import PithosClient, PithosRestClient
50 rest_pkg = 'kamaki.clients.pithos.rest_api.PithosRestClient'
51 pithos_pkg = 'kamaki.clients.pithos.PithosClient'
53 user_id = 'ac0un7-1d-5tr1ng'
57 'content-language': 'en-us',
58 'content-type': 'text/html; charset=utf-8',
59 'date': 'Wed, 06 Mar 2013 13:25:51 GMT',
60 'last-modified': 'Mon, 04 Mar 2013 18:22:31 GMT',
61 'server': 'gunicorn/0.14.5',
62 'vary': 'Accept-Language',
63 'x-account-bytes-used': '751615526',
64 'x-account-container-count': 7,
65 'x-account-policy-quota': 53687091200,
66 'x-account-policy-versioning': 'auto'}
68 'content-language': 'en-us',
69 'content-type': 'text/html; charset=utf-8',
70 'date': 'Wed, 06 Mar 2013 15:11:05 GMT',
71 'last-modified': 'Wed, 27 Feb 2013 15:56:13 GMT',
72 'server': 'gunicorn/0.14.5',
73 'vary': 'Accept-Language',
74 'x-container-block-hash': 'sha256',
75 'x-container-block-size': 4194304,
76 'x-container-bytes-used': 309528938,
77 'x-container-object-count': 14,
78 'x-container-object-meta': '',
79 'x-container-policy-quota': 53687091200,
80 'x-container-policy-versioning': 'auto'}
82 'content-language': 'en-us',
83 'content-length': 254965,
84 'content-type': 'application/octet-stream',
85 'date': 'Thu, 07 Mar 2013 13:27:43 GMT',
87 'last-modified': 'Mon, 04 Mar 2013 18:22:31 GMT',
88 'server': 'gunicorn/0.14.5',
89 'vary': 'Accept-Language',
90 'x-object-hash': 'obj3c7h45h1s0bj3c7h45h411r34dY',
91 'x-object-uuid': 'd0c747ca-34bd-49e0-8e98-1d07d8b0cbc7',
92 'x-object-version': '525996',
93 'x-object-version-timestamp': 'Mon, 04 Mar 2013 18:22:31 GMT',
94 'x-object-meta-k1': 'v1',
95 'x-object-meta-k2': 'v2'}
99 last_modified="2013-02-27T11:56:09.893033+00:00",
102 x_container_policy=dict(quota="21474836480", versioning="auto")),
105 last_modified="2012-10-23T12:25:17.229187+00:00",
108 x_container_policy=dict(quota="21474836480", versioning="auto"))]
111 name="The_Secret_Garden.zip",
112 x_object_public="/public/wdp9p",
114 x_object_version_timestamp="1360237915.7027509",
115 x_object_uuid="s0m3uu1df0r0bj0n3",
116 last_modified="2013-02-07T11:51:55.702751+00:00",
117 content_type="application/octet-stream",
118 x_object_hash="0afdf29f71cd53126225c3f54ca",
119 x_object_version=17737,
120 x_object_modified_by=user_id),
122 name="The_Revealed_Garden.zip",
123 x_object_public="/public/wpd7p",
125 x_object_version_timestamp="13602915.7027509",
126 x_object_uuid="s0m3uu1df0r0bj70w",
127 last_modified="2013-02-07T11:51:55.702751+00:00",
128 content_type="application/octet-stream",
129 x_object_hash="0afdf29f71cd53126225c3f54ca",
130 x_object_version=17737,
131 x_object_modified_by=user_id)]
132 object_hashmap = dict(
133 block_hash="sha256", block_size=4194304, bytes=33554432,
135 "4988438cc1c0292c085d289649b28cf547ba3db71c6efaac9f2df7e193d4d0af",
136 "b214244aa56df7d1df7c6cac066e7cef268d9c2beb4dcf7ce68af667b0626f91",
137 "17f365f25e0682565ded30576066bb13377a3d306967e4d74e06bb6bbc20f75f",
138 "2524ae208932669fff89adf8a2fc0df3b67736ca0d3aadce7a2ce640f142af37",
139 "5d807a2129d2fcd3c221c3da418ed52af3fc48d0817b62e0bb437acffccd3514",
140 "609de22ce842d997f645fc49d5f14e0e3766dd51a6cbe66383b2bab82c8dfcd0",
141 "3102851ac168c78be70e35ff5178c7b1ebebd589e5106d565ca1094d1ca8ff59",
142 "bfe306dd24e92a8d85caf7055643f250fd319e8c4cdd4755ddabbf3ff97e83c7"])
144 dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="0b1a-82d5"),
145 dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="0b2a-f2d5"),
146 dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="2b1a-82d6")]
150 """FR stands for Fake Response"""
161 class PithosRest(TestCase):
164 self.url = 'https://www.example.com/pithos'
165 self.token = 'p17h0570k3n'
166 self.client = PithosRestClient(self.url, self.token)
167 self.client.account = user_id
168 self.client.container = 'c0nt@1n3r_i'
175 @patch('%s.set_param' % rest_pkg)
176 @patch('%s.set_header' % rest_pkg)
177 @patch('%s.head' % rest_pkg, return_value=FR())
178 def test_account_head(self, head, SH, SP):
179 for params in product(
181 (None, '50m3-07h3r-d473'),
182 (None, 'y37-4n7h3r-d473'),
183 ((), ('someval',), ('v1', 'v2',)),
184 (dict(), dict(success=200), dict(k='v', v='k'))):
185 args, kwargs = params[-2], params[-1]
187 self.client.account_head(*(params + args), **kwargs)
189 self.assertEqual(SP.mock_calls[-1], call('until', unt, iff=unt))
190 IMS, IUS = params[1], params[2]
191 self.assertEqual(SH.mock_calls[-2:], [
192 call('If-Modified-Since', IMS),
193 call('If-Unmodified-Since', IUS)])
194 self.assertEqual(head.mock_calls[-1], call(
195 '/%s' % self.client.account,
197 success=kwargs.pop('success', 204),
200 @patch('%s.set_param' % rest_pkg)
201 @patch('%s.set_header' % rest_pkg)
202 @patch('%s.get' % rest_pkg, return_value=FR())
203 def test_account_get(self, get, SH, SP):
204 keys = ('limit', 'marker', 'format', 'shared', 'until')
205 for params in product(
211 (None, '50m3-07h3r-d473'),
212 (None, 'y37-4n7h3r-d473'),
213 ((), ('someval',), ('v1', 'v2',)),
214 (dict(), dict(success=200), dict(k='v', v='k'))):
215 args, kwargs = params[-2], params[-1]
217 self.client.account_get(*(params + args), **kwargs)
218 self.assertEqual(SP.mock_calls[-5:],
219 [call(keys[i], iff=X) if (
221 keys[i], X, iff=X) for i, X in enumerate(params[:5])])
222 IMS, IUS = params[5], params[6]
223 self.assertEqual(SH.mock_calls[-2:], [
224 call('If-Modified-Since', IMS),
225 call('If-Unmodified-Since', IUS)])
226 self.assertEqual(get.mock_calls[-1], call(
227 '/%s' % self.client.account,
229 success=kwargs.pop('success', (200, 204)),
232 @patch('%s.set_param' % rest_pkg)
233 @patch('%s.set_header' % rest_pkg)
234 @patch('%s.post' % rest_pkg, return_value=FR())
235 def test_account_post(self, post, SH, SP):
236 #keys = ('update', 'groups', 'metadata', 'quota', 'versioning')
239 ({}, dict(g=['u1', 'u2']), dict(g1=[], g2=['u1', 'u2'])),
240 (None, dict(k1='v1', k2='v2', k3='v2'), dict(k='v')),
242 (None, 'v3r510n1ng'),
243 ((), ('someval',), ('v1', 'v2',)),
244 (dict(), dict(success=200), dict(k='v', v='k'))):
245 args, kwargs = pm[-2:]
247 self.client.account_post(*(pm + args), **kwargs)
249 self.assertEqual(SP.mock_calls[-1], call('update', iff=upd))
253 call('X-Account-Group-%s' % k, v) for k, v in pm[1].items()]
256 call('X-Account-Meta-%s' % k, v) for k, v in pm[2].items()]
258 call('X-Account-Policy-Quota', pm[3]),
259 call('X-Account-Policy-Versioning', pm[4])]
260 self.assertEqual(SH.mock_calls[- len(expected):], expected)
261 self.assertEqual(post.mock_calls[-1], call(
262 '/%s' % self.client.account,
264 success=kwargs.pop('success', 202),
267 @patch('%s.set_param' % rest_pkg)
268 @patch('%s.set_header' % rest_pkg)
269 @patch('%s.head' % rest_pkg, return_value=FR())
270 def test_container_head(self, head, SH, SP):
273 (None, '47h3r-d473'),
274 (None, 'y37-4n47h3r'),
276 (dict(), dict(success=200), dict(k='v', v='k'))):
277 args, kwargs = pm[-2:]
279 self.client.container_head(*(pm + args), **kwargs)
280 unt, ims, ius = pm[0:3]
281 self.assertEqual(SP.mock_calls[-1], call('until', unt, iff=unt))
282 self.assertEqual(SH.mock_calls[-2:], [
283 call('If-Modified-Since', ims),
284 call('If-Unmodified-Since', ius)])
285 self.assertEqual(head.mock_calls[-1], call(
286 '/%s/%s' % (self.client.account, self.client.container),
288 success=kwargs.pop('success', 204),
291 @patch('%s.set_param' % rest_pkg)
292 @patch('%s.set_header' % rest_pkg)
293 @patch('%s.get' % rest_pkg, return_value=FR())
294 def test_container_get(self, get, SH, SP):
298 (None, 'some/prefix'),
300 (None, '/some/path'),
301 ('json', 'some-format'),
302 ([], ['k1', 'k2', 'k3']),
304 (None, 'unt1l-d473'),
305 (None, 'y37-4n47h3r'),
306 (None, '4n47h3r-d473'),
308 (dict(), dict(success=400), dict(k='v', v='k'))):
309 args, kwargs = pm[-2:]
311 self.client.container_get(*(pm + args), **kwargs)
312 lmt, mrk, prfx, dlm, path, frmt, meta, shr, unt = pm[:-2]
313 exp = [call('limit', lmt, iff=lmt), call('marker', mrk, iff=mrk)]
314 exp += [call('path', path)] if path else [
315 call('prefix', prfx, iff=prfx),
316 call('delimiter', dlm, iff=dlm)]
317 exp += [call('format', frmt, iff=frmt), call('shared', iff=shr)]
319 exp += [call('meta', ','.join(meta))]
320 exp += [call('until', unt, iff=unt)]
321 self.assertEqual(SP.mock_calls[- len(exp):], exp)
323 self.assertEqual(SH.mock_calls[-2:], [
324 call('If-Modified-Since', ims),
325 call('If-Unmodified-Since', ius)])
326 self.assertEqual(get.mock_calls[-1], call(
327 '/%s/%s' % (self.client.account, self.client.container),
329 success=kwargs.pop('success', 200),
332 @patch('%s.set_header' % rest_pkg)
333 @patch('%s.put' % rest_pkg, return_value=FR())
334 def test_container_put(self, put, SH):
337 (None, 'v3r51on1ng'),
338 (dict(), dict(k1='v2'), dict(k2='v2', k3='v3')),
340 (dict(), dict(success=400), dict(k='v', v='k'))):
341 args, kwargs = pm[-2:]
343 self.client.container_put(*(pm + args), **kwargs)
344 quota, versioning, metas = pm[-3:]
346 call('X-Container-Policy-Quota', quota),
347 call('X-Container-Policy-Versioning', versioning)] + [
348 call('X-Container-Meta-%s' % k, v) for k, v in metas.items()]
349 self.assertEqual(SH.mock_calls[- len(exp):], exp)
350 self.assertEqual(put.mock_calls[-1], call(
351 '/%s/%s' % (self.client.account, self.client.container),
353 success=kwargs.pop('success', (201, 202)),
356 @patch('%s.set_param' % rest_pkg)
357 @patch('%s.set_header' % rest_pkg)
358 @patch('%s.post' % rest_pkg, return_value=FR())
359 def test_container_post(self, post, SH, SP):
362 ('json', 'some-format'),
364 (None, 'v3r51on1ng'),
365 (dict(), dict(k1='v2'), dict(k2='v2', k3='v3')),
366 (None, 'content-type'),
368 (None, 'transfer-encoding'),
370 (dict(), dict(success=400), dict(k='v', v='k'))):
371 args, kwargs = pm[-2:]
373 self.client.container_post(*(pm + args), **kwargs)
375 self.assertEqual(SP.mock_calls[-2:], [
376 call('update', iff=upd),
377 call('format', frmt, iff=frmt)])
378 qta, vrs, metas, ctype, clen, trenc = pm[2:]
379 prfx = 'X-Container-Meta-'
381 call('X-Container-Policy-Quota', qta),
382 call('X-Container-Policy-Versioning', vrs)] + [
383 call('%s%s' % (prfx, k), v) for k, v in metas.items()] + [
384 call('Content-Type', ctype),
385 call('Content-Length', clen),
386 call('Transfer-Encoding', trenc)]
387 self.assertEqual(SH.mock_calls[- len(exp):], exp)
389 self.assertEqual(post.mock_calls[-1], call(
390 '/%s/%s' % (self.client.account, self.client.container),
392 success=kwargs.pop('success', 202),
395 @patch('%s.set_param' % rest_pkg)
396 @patch('%s.delete' % rest_pkg, return_value=FR())
397 def test_container_delete(self, delete, SP):
402 (dict(), dict(success=400), dict(k='v', v='k'))):
403 args, kwargs = pm[-2:]
405 self.client.container_delete(*(pm + args), **kwargs)
407 self.assertEqual(SP.mock_calls[-2:], [
408 call('until', unt, iff=unt),
409 call('delimiter', dlm, iff=dlm)])
410 self.assertEqual(delete.mock_calls[-1], call(
411 '/%s/%s' % (self.client.account, self.client.container),
413 success=kwargs.pop('success', 204),
416 @patch('%s.set_param' % rest_pkg)
417 @patch('%s.set_header' % rest_pkg)
418 @patch('%s.head' % rest_pkg, return_value=FR())
419 def test_object_head(self, head, SH, SP):
424 (None, '1f-m0d-51nc3'),
425 (None, '1f-unm0d-51nc3'),
427 (dict(), dict(success=400), dict(k='v', v='k'))):
428 args, kwargs = pm[-2:]
430 self.client.object_head(obj, *(pm + args), **kwargs)
431 vrs, etag, netag, ims, ius = pm[:5]
434 call('version', vrs, iff=vrs))
435 self.assertEqual(SH.mock_calls[-4:], [
436 call('If-Match', etag),
437 call('If-None-Match', netag),
438 call('If-Modified-Since', ims),
439 call('If-Unmodified-Since', ius)])
440 acc, cont = self.client.account, self.client.container
441 self.assertEqual(head.mock_calls[-1], call(
442 '/%s/%s/%s' % (acc, cont, obj),
444 success=kwargs.pop('success', 200),
447 @patch('%s.set_param' % rest_pkg)
448 @patch('%s.set_header' % rest_pkg)
449 @patch('%s.get' % rest_pkg, return_value=FR())
450 def test_object_get(self, get, SH, SP):
455 (None, 'range=74-63'),
462 (dict(), dict(success=400), dict(k='v', v='k'))):
463 args, kwargs = pm[-2:]
465 self.client.object_get(obj, *(pm + args), **kwargs)
466 format, hashmap, version = pm[:3]
467 self.assertEqual(SP.mock_calls[-3:], [
468 call('format', format, iff=format),
469 call('hashmap', hashmap, iff=hashmap),
470 call('version', version, iff=version)])
471 rng, ifrng, im, inm, ims, ius = pm[-6:]
472 self.assertEqual(SH.mock_calls[-6:], [
474 call('If-Range', '', ifrng and rng),
475 call('If-Match', im),
476 call('If-None-Match', inm),
477 call('If-Modified-Since', ims),
478 call('If-Unmodified-Since', ius)])
479 acc, cont = self.client.account, self.client.container
480 self.assertEqual(get.mock_calls[-1], call(
481 '/%s/%s/%s' % (acc, cont, obj),
483 success=kwargs.pop('success', 200),
486 @patch('%s.set_param' % rest_pkg)
487 @patch('%s.set_header' % rest_pkg)
488 @patch('%s.put' % rest_pkg, return_value=FR())
489 def test_object_put(self, put, SH, SP):
494 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
496 (dict(), dict(k2='v2', k3='v3')),
498 (dict(), dict(success=400), dict(k='v', v='k'))):
499 args, kwargs = pm[-2:]
502 for i in range(len(terms)):
504 terms[i] = 'val_%s' % randint(13, 1024)
505 self.client.object_put(
507 *(pm[:3] + tuple(terms) + pm[3:] + args),
509 format, hashmap, delimiter = pm[:3]
510 self.assertEqual(SP.mock_calls[-3:], [
511 call('format', format, iff=format),
512 call('hashmap', hashmap, iff=hashmap),
513 call('delimiter', delimiter, iff=delimiter)])
515 im, inm, etag, clen, ctype, trenc,
516 cp, mv, srcacc, srcvrs, conenc, condis, mnf) = terms
517 perms, public, metas = pm[3:]
519 call('If-Match', im),
520 call('If-None-Match', inm),
522 call('Content-Length', clen),
523 call('Content-Type', ctype),
524 call('Transfer-Encoding', trenc),
525 call('X-Copy-From', cp),
526 call('X-Move-From', mv),
527 call('X-Source-Account', srcacc),
528 call('X-Source-Version', srcvrs),
529 call('Content-Encoding', conenc),
530 call('Content-Disposition', condis),
531 call('X-Object-Manifest', mnf)]
534 for ptype, pval in perms.items():
536 perm_str += ';' if perm_str else ''
537 perm_str += '%s=%s' % (ptype, ','.join(pval))
538 exp += [call('X-Object-Sharing', perm_str)]
539 exp += [call('X-Object-Public', public)]
540 for k, v in metas.items():
541 exp += [call('X-Object-Meta-%s' % k, v)]
542 self.assertEqual(SH.mock_calls[- len(exp):], exp)
543 acc, cont = self.client.account, self.client.container
544 self.assertEqual(put.mock_calls[-1], call(
545 '/%s/%s/%s' % (acc, cont, obj),
547 success=kwargs.pop('success', 201),
550 @patch('%s.set_param' % rest_pkg)
551 @patch('%s.set_header' % rest_pkg)
552 @patch('%s.copy' % rest_pkg, return_value=FR())
553 def test_object_copy(self, copy, SH, SP):
559 (None, 'ifnonematch'),
560 (None, 'destinationaccount'),
561 (None, 'content-type'),
562 (None, 'content-encoding'),
563 (None, 'content-disp'),
564 (None, 'source-version'),
565 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
567 (dict(), dict(k2='v2', k3='v3')),
569 (dict(), dict(success=400), dict(k='v', v='k'))):
570 args, kwargs = pm[-2:]
572 self.client.object_copy(obj, dest, *(pm + args), **kwargs)
574 self.assertEqual(SP.mock_calls[-2:], [
575 call('format', format, iff=format),
576 call('ignore_content_type', iff=ict)])
577 im, inm, da, ct, ce, cd, sv, perms, public, metas = pm[2:]
578 exp = [call('If-Match', im),
579 call('If-None-Match', inm),
580 call('Destination', dest),
581 call('Destination-Account', da),
582 call('Content-Type', ct),
583 call('Content-Encoding', ce),
584 call('Content-Disposition', cd),
585 call('X-Source-Version', sv)]
588 for ptype, pval in perms.items():
590 perm_str += ';' if perm_str else ''
591 perm_str += '%s=%s' % (ptype, ','.join(pval))
592 exp += [call('X-Object-Sharing', perm_str)]
593 exp += [call('X-Object-Public', public)]
594 for k, v in metas.items():
595 exp += [call('X-Object-Meta-%s' % k, v)]
596 self.assertEqual(SH.mock_calls[- len(exp):], exp)
597 acc, cont = self.client.account, self.client.container
598 self.assertEqual(copy.mock_calls[-1], call(
599 '/%s/%s/%s' % (acc, cont, obj),
601 success=kwargs.pop('success', 201),
604 @patch('%s.set_param' % rest_pkg)
605 @patch('%s.set_header' % rest_pkg)
606 @patch('%s.move' % rest_pkg, return_value=FR())
607 def test_object_move(self, move, SH, SP):
612 (None, 'ifnonematch'),
613 (None, 'destination'),
614 (None, 'destinationaccount'),
615 (None, 'content-type'),
616 (None, 'content-encoding'),
617 (None, 'content-disp'),
618 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
620 (dict(), dict(k2='v2', k3='v3')),
622 (dict(), dict(success=400), dict(k='v', v='k'))):
623 args, kwargs = pm[-2:]
625 self.client.object_move(obj, *(pm + args), **kwargs)
627 self.assertEqual(SP.mock_calls[-2:], [
628 call('format', format, iff=format),
629 call('ignore_content_type', iff=ict)])
630 im, inm, d, da, ct, ce, cd, perms, public, metas = pm[2:]
631 exp = [call('If-Match', im),
632 call('If-None-Match', inm),
633 call('Destination', d),
634 call('Destination-Account', da),
635 call('Content-Type', ct),
636 call('Content-Encoding', ce),
637 call('Content-Disposition', cd)]
640 for ptype, pval in perms.items():
642 perm_str += ';' if perm_str else ''
643 perm_str += '%s=%s' % (ptype, ','.join(pval))
644 exp += [call('X-Object-Sharing', perm_str)]
645 exp += [call('X-Object-Public', public)]
646 for k, v in metas.items():
647 exp += [call('X-Object-Meta-%s' % k, v)]
648 self.assertEqual(SH.mock_calls[- len(exp):], exp)
649 acc, cont = self.client.account, self.client.container
650 self.assertEqual(move.mock_calls[-1], call(
651 '/%s/%s/%s' % (acc, cont, obj),
653 success=kwargs.pop('success', 201),
657 class Pithos(TestCase):
661 def _create_temp_file(self, num_of_blocks):
662 self.files.append(NamedTemporaryFile())
663 tmpFile = self.files[-1]
664 file_size = num_of_blocks * 4 * 1024 * 1024
665 print('\n\tCreate tmp file')
666 tmpFile.write(urandom(file_size))
672 def assert_dicts_are_equal(self, d1, d2):
673 for k, v in d1.items():
674 self.assertTrue(k in d2)
675 if isinstance(v, dict):
676 self.assert_dicts_are_equal(v, d2[k])
678 self.assertEqual(unicode(v), unicode(d2[k]))
681 self.url = 'https://www.example.com/pithos'
682 self.token = 'p17h0570k3n'
683 self.client = PithosClient(self.url, self.token)
684 self.client.account = user_id
685 self.client.container = 'c0nt@1n3r_i'
695 # Pithos+ methods that extend storage API
697 @patch('%s.account_head' % pithos_pkg, return_value=FR())
698 def test_get_account_info(self, AH):
699 FR.headers = account_info
700 for until in (None, 'un71L-d473'):
701 r = self.client.get_account_info(until=until)
702 self.assert_dicts_are_equal(r, account_info)
703 self.assertEqual(AH.mock_calls[-1], call(until=until))
705 self.assertRaises(ClientError, self.client.get_account_info)
707 @patch('%s.account_post' % pithos_pkg, return_value=FR())
708 def test_del_account_meta(self, AP):
709 keys = ['k1', 'k2', 'k3']
711 self.client.del_account_meta(key)
714 call(update=True, metadata={key: ''}))
716 @patch('%s.container_head' % pithos_pkg, return_value=FR())
717 def test_get_container_info(self, CH):
718 FR.headers = container_info
719 r = self.client.get_container_info()
720 self.assert_dicts_are_equal(r, container_info)
722 r = self.client.get_container_info(until=u)
723 self.assertEqual(CH.mock_calls, [call(until=None), call(until=u)])
725 @patch('%s.account_get' % pithos_pkg, return_value=FR())
726 def test_list_containers(self, get):
727 FR.json = container_list
728 r = self.client.list_containers()
729 get.assert_called_once_with()
730 for i in range(len(r)):
731 self.assert_dicts_are_equal(r[i], container_list[i])
733 @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
734 @patch('%s.container_post' % pithos_pkg, return_value=FR())
735 @patch('%s.object_put' % pithos_pkg, return_value=FR())
736 def test_upload_object(self, OP, CP, GCI):
738 tmpFile = self._create_temp_file(num_of_blocks)
741 self.client.upload_object(obj, tmpFile)
742 self.assertEqual(GCI.mock_calls[-1], call())
743 [call1, call2] = OP.mock_calls
745 (args1, kwargs1) = call1[1:3]
746 (args2, kwargs2) = call2[1:3]
747 self.assertEqual(args1, (obj,))
753 hashes=['s0m3h@5h'] * num_of_blocks,
754 bytes=num_of_blocks * 4 * 1024 * 1024),
756 content_encoding=None,
757 content_type='application/octet-stream',
758 content_disposition=None,
761 for k, v in expected1.items():
763 self.assertEqual(len(v['hashes']), len(kwargs1[k]['hashes']))
764 self.assertEqual(v['bytes'], kwargs1[k]['bytes'])
766 self.assertEqual(v, kwargs1[k])
768 (args2, kwargs2) = call2[1:3]
769 self.assertEqual(args2, (obj,))
772 hashes=['s0m3h@5h'] * num_of_blocks,
773 bytes=num_of_blocks * 4 * 1024 * 1024),
774 content_type='application/octet-stream',
778 for k, v in expected2.items():
780 self.assertEqual(len(v['hashes']), len(kwargs2[k]['hashes']))
781 self.assertEqual(v['bytes'], kwargs2[k]['bytes'])
783 self.assertEqual(v, kwargs2[k])
789 from progress.bar import ShadyBar
790 blck_bar = ShadyBar('Mock blck calc.')
791 upld_bar = ShadyBar('Mock uplds')
796 if blck_bar and upld_bar:
799 for i in blck_bar.iter(range(n)):
804 for i in upld_bar.iter(range(n)):
809 self.client.upload_object(
811 hash_cb=blck_gen, upload_cb=upld_gen)
813 for i, c in enumerate(OP.mock_calls[-mock_offset:]):
814 self.assertEqual(OP.mock_calls[i], c)
819 sharing = dict(read=['u1', 'g1', 'u2'], write=['u1'])
820 self.client.upload_object(obj, tmpFile,
821 content_type=ctype, sharing=sharing)
822 self.assertEqual(OP.mock_calls[-1][2]['content_type'], ctype)
823 self.assert_dicts_are_equal(
824 OP.mock_calls[-2][2]['permissions'],
832 content_disposition=ctype + 'd15p051710n',
834 content_encoding='802.11')
835 self.client.upload_object(obj, tmpFile, **kwargs)
836 for arg, val in kwargs.items():
837 self.assertEqual(OP.mock_calls[-2][2][arg], val)
839 def test_get_object_info(self):
840 FR.headers = object_info
843 PithosClient, 'object_head',
844 return_value=FR()) as head:
845 r = self.client.get_object_info(obj)
846 self.assertEqual(r, object_info)
847 r = self.client.get_object_info(obj, version=version)
848 self.assertEqual(head.mock_calls, [
849 call(obj, version=None),
850 call(obj, version=version)])
852 PithosClient, 'object_head',
853 side_effect=ClientError('Obj not found', 404)):
856 self.client.get_object_info,
857 obj, version=version)
859 @patch('%s.get_object_info' % pithos_pkg, return_value=object_info)
860 def test_get_object_meta(self, GOI):
861 for version in (None, 'v3r510n'):
862 r = self.client.get_object_meta(obj, version)
863 for k in [k for k in object_info if k.startswith('x-object-meta')]:
864 self.assertEqual(r.pop(k), object_info[k])
865 self.assertFalse(len(r))
866 self.assertEqual(GOI.mock_calls[-1], call(obj, version=version))
868 @patch('%s.object_post' % pithos_pkg, return_value=FR())
869 def test_del_object_meta(self, post):
870 metakey = '50m3m3t4k3y'
871 self.client.del_object_meta(obj, metakey)
872 post.assert_called_once_with(obj, update=True, metadata={metakey: ''})
874 @patch('%s.object_put' % pithos_pkg, return_value=FR())
875 def test_copy_object(self, put):
876 src_cont = 'src-c0nt41n3r'
878 dst_cont = 'dst-c0nt41n3r'
885 copy_from='/%s/%s' % (src_cont, src_obj),
890 self.client.copy_object(src_cont, src_obj, dst_cont)
891 self.assertEqual(put.mock_calls[-1], expected)
892 self.client.copy_object(src_cont, src_obj, dst_cont, dst_obj)
893 self.assertEqual(put.mock_calls[-1][1], (dst_obj,))
895 source_version='src-v3r510n',
896 source_account='src-4cc0un7',
898 content_type='c0n73n7Typ3',
900 self.client.copy_object(src_cont, src_obj, dst_cont, **kwargs)
901 for k, v in kwargs.items():
902 self.assertEqual(v, put.mock_calls[-1][2][k])
904 @patch('%s.object_put' % pithos_pkg, return_value=FR())
905 def test_move_object(self, put):
906 src_cont = 'src-c0nt41n3r'
908 dst_cont = 'dst-c0nt41n3r'
915 move_from='/%s/%s' % (src_cont, src_obj),
920 self.client.move_object(src_cont, src_obj, dst_cont)
921 self.assertEqual(put.mock_calls[-1], expected)
922 self.client.move_object(src_cont, src_obj, dst_cont, dst_obj)
923 self.assertEqual(put.mock_calls[-1][1], (dst_obj,))
925 source_version='src-v3r510n',
926 source_account='src-4cc0un7',
928 content_type='c0n73n7Typ3',
930 self.client.move_object(src_cont, src_obj, dst_cont, **kwargs)
931 for k, v in kwargs.items():
932 self.assertEqual(v, put.mock_calls[-1][2][k])
934 # Pithos+ only methods
936 @patch('%s.container_delete' % pithos_pkg, return_value=FR())
937 def test_purge_container(self, CD):
938 self.client.purge_container()
939 self.assertTrue('until' in CD.mock_calls[-1][2])
940 cont = self.client.container
941 self.client.purge_container('another-container')
942 self.assertEqual(self.client.container, cont)
944 @patch('%s.object_put' % pithos_pkg, return_value=FR())
945 def test_upload_object_unchunked(self, put):
947 tmpFile = self._create_temp_file(num_of_blocks)
950 data=num_of_blocks * 4 * 1024 * 1024,
952 content_encoding='some content_encoding',
953 content_type='some content-type',
954 content_disposition='some content_disposition',
956 permissions=dict(read=['u1', 'g1', 'u2'], write=['u1']))
957 self.client.upload_object_unchunked(obj, tmpFile)
958 self.assertEqual(put.mock_calls[-1][1], (obj,))
960 sorted(put.mock_calls[-1][2].keys()),
961 sorted(expected.keys()))
962 kwargs = dict(expected)
963 kwargs.pop('success')
964 kwargs['size'] = kwargs.pop('data')
965 kwargs['sharing'] = kwargs.pop('permissions')
967 self.client.upload_object_unchunked(obj, tmpFile, **kwargs)
968 pmc = put.mock_calls[-1][2]
969 for k, v in expected.items():
971 self.assertEqual(len(pmc[k]), v)
973 self.assertEqual(pmc[k], v)
976 self.client.upload_object_unchunked,
977 obj, tmpFile, withHashFile=True)
979 @patch('%s.object_put' % pithos_pkg, return_value=FR())
980 def test_create_object_by_manifestation(self, put):
981 manifest = '%s/%s' % (self.client.container, obj)
984 content_encoding='some content_encoding',
985 content_type='some content-type',
986 content_disposition='some content_disposition',
988 sharing=dict(read=['u1', 'g1', 'u2'], write=['u1']))
989 self.client.create_object_by_manifestation(obj)
990 expected = dict(content_length=0, manifest=manifest)
992 expected['permissions' if k == 'sharing' else k] = None
993 self.assertEqual(put.mock_calls[-1], call(obj, **expected))
994 self.client.create_object_by_manifestation(obj, **kwargs)
995 expected.update(kwargs)
996 expected['permissions'] = expected.pop('sharing')
997 self.assertEqual(put.mock_calls[-1], call(obj, **expected))
999 @patch('%s.get_object_hashmap' % pithos_pkg, return_value=object_hashmap)
1000 @patch('%s.object_get' % pithos_pkg, return_value=FR())
1001 def test_download_object(self, GET, GOH):
1003 tmpFile = self._create_temp_file(num_of_blocks)
1004 FR.content = tmpFile.read(4 * 1024 * 1024)
1005 tmpFile = self._create_temp_file(num_of_blocks)
1006 num_of_blocks = len(object_hashmap['hashes'])
1011 if_match='if and only if',
1012 if_none_match='if and only not',
1013 if_modified_since='what if not?',
1014 if_unmodified_since='this happens if not!',
1015 async_headers=dict(Range='bytes=0-88888888'))
1017 self.client.download_object(obj, tmpFile)
1018 self.assertEqual(len(GET.mock_calls), num_of_blocks)
1019 self.assertEqual(GET.mock_calls[-1][1], (obj,))
1020 for k, v in kwargs.items():
1021 if k == 'async_headers':
1022 self.assertTrue('Range' in GET.mock_calls[-1][2][k])
1023 elif k in ('resume', 'range_str'):
1026 self.assertEqual(GET.mock_calls[-1][2][k], None)
1028 # Check ranges are consecutive
1031 for c in GET.mock_calls:
1032 rng_str = c[2]['async_headers']['Range']
1033 (start, rng_str) = rng_str.split('=')
1034 (start, end) = rng_str.split('-')
1035 starts.append(start)
1038 for i, start in enumerate(sorted(starts)):
1040 int(ends[i - 1]) == int(start) - 1
1042 # With progress bars
1044 from progress.bar import ShadyBar
1045 dl_bar = ShadyBar('Mock dl')
1052 for i in dl_bar.iter(range(n)):
1057 self.client.download_object(obj, tmpFile, download_cb=blck_gen)
1058 self.assertEqual(len(GET.mock_calls), 2 * num_of_blocks)
1061 kwargs.pop('async_headers')
1062 kwargs.pop('resume')
1063 self.client.download_object(obj, tmpFile, **kwargs)
1064 for k, v in kwargs.items():
1065 if k == 'range_str':
1067 GET.mock_calls[-1][2]['data_range'],
1070 self.assertEqual(GET.mock_calls[-1][2][k], v)
1072 # ALl options on no tty
1078 tmpFile.isatty = foo
1079 self.client.download_object(obj, tmpFile, **kwargs)
1080 for k, v in kwargs.items():
1081 if k == 'range_str':
1082 self.assertTrue('data_range' in GET.mock_calls[-1][2])
1084 self.assertEqual(GET.mock_calls[-1][2][k], v)
1086 def test_get_object_hashmap(self):
1087 FR.json = object_hashmap
1088 for empty in (304, 412):
1090 PithosClient, 'object_get',
1091 side_effect=ClientError('Empty', status=empty)):
1092 r = self.client.get_object_hashmap(obj)
1093 self.assertEqual(r, {})
1099 if_etag_not_match=None,
1100 if_modified_since=None,
1101 if_unmodified_since=None)
1103 version='s0m3v3r51on',
1104 if_match='if match',
1105 if_none_match='if non match',
1106 if_modified_since='some date here',
1107 if_unmodified_since='some date here',
1110 PithosClient, 'object_get',
1111 return_value=FR()) as get:
1112 r = self.client.get_object_hashmap(obj)
1113 self.assertEqual(r, object_hashmap)
1114 self.assertEqual(get.mock_calls[-1], call(obj, **exp_args))
1115 r = self.client.get_object_hashmap(obj, **kwargs)
1116 exp_args['if_etag_match'] = kwargs.pop('if_match')
1117 exp_args['if_etag_not_match'] = kwargs.pop('if_none_match')
1118 exp_args.update(kwargs)
1119 self.assertEqual(get.mock_calls[-1], call(obj, **exp_args))
1121 @patch('%s.account_post' % pithos_pkg, return_value=FR())
1122 def test_set_account_group(self, post):
1123 (group, usernames) = ('aU53rGr0up', ['u1', 'u2', 'u3'])
1124 self.client.set_account_group(group, usernames)
1125 post.assert_called_once_with(update=True, groups={group: usernames})
1127 @patch('%s.account_post' % pithos_pkg, return_value=FR())
1128 def test_del_account_group(self, post):
1129 group = 'aU53rGr0up'
1130 self.client.del_account_group(group)
1131 post.assert_called_once_with(update=True, groups={group: []})
1133 @patch('%s.get_account_info' % pithos_pkg, return_value=account_info)
1134 def test_get_account_quota(self, GAI):
1135 key = 'x-account-policy-quota'
1136 r = self.client.get_account_quota()
1137 GAI.assert_called_once_with()
1138 self.assertEqual(r[key], account_info[key])
1140 @patch('%s.get_account_info' % pithos_pkg, return_value=account_info)
1141 def test_get_account_versioning(self, GAI):
1142 key = 'x-account-policy-versioning'
1143 r = self.client.get_account_versioning()
1144 GAI.assert_called_once_with()
1145 self.assertEqual(r[key], account_info[key])
1147 def test_get_account_meta(self):
1148 key = 'x-account-meta-'
1150 PithosClient, 'get_account_info',
1151 return_value=account_info):
1152 r = self.client.get_account_meta()
1153 keys = [k for k in r if k.startswith(key)]
1154 self.assertFalse(keys)
1155 acc_info = dict(account_info)
1156 acc_info['%sk1' % key] = 'v1'
1157 acc_info['%sk2' % key] = 'v2'
1158 acc_info['%sk3' % key] = 'v3'
1160 PithosClient, 'get_account_info',
1161 return_value=acc_info):
1162 r = self.client.get_account_meta()
1163 for k in [k for k in acc_info if k.startswith(key)]:
1164 self.assertEqual(r[k], acc_info[k])
1166 def test_get_account_group(self):
1167 key = 'x-account-group-'
1169 PithosClient, 'get_account_info',
1170 return_value=account_info):
1171 r = self.client.get_account_group()
1172 keys = [k for k in r if k.startswith(key)]
1173 self.assertFalse(keys)
1174 acc_info = dict(account_info)
1175 acc_info['%sk1' % key] = 'g1'
1176 acc_info['%sk2' % key] = 'g2'
1177 acc_info['%sk3' % key] = 'g3'
1179 PithosClient, 'get_account_info',
1180 return_value=acc_info):
1181 r = self.client.get_account_group()
1182 for k in [k for k in acc_info if k.startswith(key)]:
1183 self.assertEqual(r[k], acc_info[k])
1185 @patch('%s.account_post' % pithos_pkg, return_value=FR())
1186 def test_set_account_meta(self, post):
1187 metas = dict(k1='v1', k2='v2', k3='v3')
1188 self.client.set_account_meta(metas)
1189 post.assert_called_once_with(update=True, metadata=metas)
1191 @patch('%s.account_post' % pithos_pkg, return_value=FR())
1192 def test_set_account_quota(self, post):
1194 self.client.set_account_quota(qu)
1195 post.assert_called_once_with(update=True, quota=qu)
1197 @patch('%s.account_post' % pithos_pkg, return_value=FR())
1198 def test_set_account_versioning(self, post):
1199 vrs = 'n3wV3r51on1ngTyp3'
1200 self.client.set_account_versioning(vrs)
1201 post.assert_called_once_with(update=True, versioning=vrs)
1203 @patch('%s.container_delete' % pithos_pkg, return_value=FR())
1204 def test_del_container(self, delete):
1206 dict(delimiter=None, until=None),
1207 dict(delimiter='X', until='50m3d473')):
1208 self.client.del_container(**kwarg)
1209 expected = dict(kwarg)
1210 expected['success'] = (204, 404, 409)
1211 self.assertEqual(delete.mock_calls[-1], call(**expected))
1212 for status_code in (404, 409):
1213 FR.status_code = status_code
1214 self.assertRaises(ClientError, self.client.del_container)
1216 @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1217 def test_get_container_versioning(self, GCI):
1218 key = 'x-container-policy-versioning'
1220 bu_cnt = self.client.container
1221 for container in (None, cont):
1222 r = self.client.get_container_versioning(container=container)
1223 self.assertEqual(r[key], container_info[key])
1224 self.assertEqual(GCI.mock_calls[-1], call())
1225 self.assertEqual(bu_cnt, self.client.container)
1227 @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1228 def test_get_container_quota(self, GCI):
1229 key = 'x-container-policy-quota'
1231 bu_cnt = self.client.container
1232 for container in (None, cont):
1233 r = self.client.get_container_quota(container=container)
1234 self.assertEqual(r[key], container_info[key])
1235 self.assertEqual(GCI.mock_calls[-1], call())
1236 self.assertEqual(bu_cnt, self.client.container)
1238 def test_get_container_meta(self):
1239 somedate = '50m3d473'
1240 key = 'x-container-meta'
1241 metaval = '50m3m374v41'
1242 container_plus = dict(container_info)
1243 container_plus[key] = metaval
1244 for ret in ((container_info, {}), (container_plus, {key: metaval})):
1247 'get_container_info',
1248 return_value=ret[0]) as GCI:
1249 for until in (None, somedate):
1250 r = self.client.get_container_meta(until=until)
1251 self.assertEqual(r, ret[1])
1252 self.assertEqual(GCI.mock_calls[-1], call(until=until))
1254 def test_get_container_object_meta(self):
1255 somedate = '50m3d473'
1256 key = 'x-container-object-meta'
1257 metaval = '50m3m374v41'
1258 container_plus = dict(container_info)
1259 container_plus[key] = metaval
1261 (container_info, {key: ''}),
1262 (container_plus, {key: metaval})):
1265 'get_container_info',
1266 return_value=ret[0]) as GCI:
1267 for until in (None, somedate):
1268 r = self.client.get_container_object_meta(until=until)
1269 self.assertEqual(r, ret[1])
1270 self.assertEqual(GCI.mock_calls[-1], call(until=until))
1272 @patch('%s.container_post' % pithos_pkg, return_value=FR())
1273 def test_set_container_meta(self, post):
1274 metas = dict(k1='v1', k2='v2', k3='v3')
1275 self.client.set_container_meta(metas)
1276 post.assert_called_once_with(update=True, metadata=metas)
1278 @patch('%s.container_post' % pithos_pkg, return_value=FR())
1279 def test_del_container_meta(self, AP):
1280 self.client.del_container_meta('somekey')
1281 AP.assert_called_once_with(update=True, metadata={'somekey': ''})
1283 @patch('%s.container_post' % pithos_pkg, return_value=FR())
1284 def test_set_container_quota(self, post):
1286 self.client.set_container_quota(qu)
1287 post.assert_called_once_with(update=True, quota=qu)
1289 @patch('%s.container_post' % pithos_pkg, return_value=FR())
1290 def test_set_container_versioning(self, post):
1291 vrs = 'n3wV3r51on1ngTyp3'
1292 self.client.set_container_versioning(vrs)
1293 post.assert_called_once_with(update=True, versioning=vrs)
1295 @patch('%s.object_delete' % pithos_pkg, return_value=FR())
1296 def test_del_object(self, delete):
1298 dict(delimiter=None, until=None),
1299 dict(delimiter='X', until='50m3d473')):
1300 self.client.del_object(obj, **kwarg)
1301 self.assertEqual(delete.mock_calls[-1], call(obj, **kwarg))
1303 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1304 def test_set_object_meta(self, post):
1305 metas = dict(k1='v1', k2='v2', k3='v3')
1308 self.client.set_object_meta,
1309 obj, 'Non dict arg')
1310 self.client.set_object_meta(obj, metas)
1311 post.assert_called_once_with(obj, update=True, metadata=metas)
1313 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1314 def test_publish_object(self, post):
1315 oinfo = dict(object_info)
1317 oinfo['x-object-public'] = val
1319 PithosClient, 'get_object_info',
1320 return_value=oinfo) as GOF:
1321 r = self.client.publish_object(obj)
1323 post.mock_calls[-1],
1324 call(obj, public=True, update=True))
1325 self.assertEqual(GOF.mock_calls[-1], call(obj))
1326 self.assertEqual(r, '%s%s' % (self.url[:-6], val))
1328 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1329 def test_unpublish_object(self, post):
1330 self.client.unpublish_object(obj)
1331 post.assert_called_once_with(obj, public=False, update=True)
1333 def test_get_object_sharing(self):
1334 info = dict(object_info)
1335 expected = dict(read='u1,g1,u2', write='u1')
1336 info['x-object-sharing'] = '; '.join(
1337 ['%s=%s' % (k, v) for k, v in expected.items()])
1339 PithosClient, 'get_object_info',
1340 return_value=info) as GOF:
1341 r = self.client.get_object_sharing(obj)
1342 self.assertEqual(GOF.mock_calls[-1], call(obj))
1343 self.assert_dicts_are_equal(r, expected)
1344 info['x-object-sharing'] = '//'.join(
1345 ['%s=%s' % (k, v) for k, v in expected.items()])
1348 self.client.get_object_sharing,
1350 info['x-object-sharing'] = '; '.join(
1351 ['%s:%s' % (k, v) for k, v in expected.items()])
1354 self.client.get_object_sharing,
1356 info['x-object-sharing'] = 'read=%s' % expected['read']
1357 r = self.client.get_object_sharing(obj)
1358 expected.pop('write')
1359 self.assert_dicts_are_equal(r, expected)
1361 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1362 def test_set_object_sharing(self, OP):
1363 read_perms = ['u1', 'g1', 'u2', 'g2']
1364 write_perms = ['u1', 'g1']
1366 dict(read_permition=read_perms, write_permition=write_perms),
1367 dict(read_permition=read_perms),
1368 dict(write_permition=write_perms),
1370 self.client.set_object_sharing(obj, **kwargs)
1371 kwargs['read'] = kwargs.pop('read_permition', '')
1372 kwargs['write'] = kwargs.pop('write_permition', '')
1375 call(obj, update=True, permissions=kwargs))
1377 @patch('%s.set_object_sharing' % pithos_pkg)
1378 def test_del_object_sharing(self, SOS):
1379 self.client.del_object_sharing(obj)
1380 SOS.assert_called_once_with(obj)
1382 @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1383 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1384 def test_append_object(self, post, GCI):
1386 tmpFile = self._create_temp_file(num_of_blocks)
1388 file_size = tmpFile.tell()
1389 for turn in range(2):
1393 from progress.bar import ShadyBar
1394 apn_bar = ShadyBar('Mock append')
1401 for i in apn_bar.iter(range(n)):
1408 self.client.append_object(
1410 upload_cb=append_gen if turn else None)
1411 self.assertEqual((turn + 1) * num_of_blocks, len(post.mock_calls))
1412 (args, kwargs) = post.mock_calls[-1][1:3]
1413 self.assertEqual(args, (obj,))
1414 self.assertEqual(kwargs['content_length'], len(kwargs['data']))
1415 fsize = num_of_blocks * int(kwargs['content_length'])
1416 self.assertEqual(fsize, file_size)
1417 self.assertEqual(kwargs['content_range'], 'bytes */*')
1418 exp = 'application/octet-stream'
1419 self.assertEqual(kwargs['content_type'], exp)
1420 self.assertEqual(kwargs['update'], True)
1422 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1423 def test_truncate_object(self, post):
1425 self.client.truncate_object(obj, upto_bytes)
1426 post.assert_called_once_with(
1429 object_bytes=upto_bytes,
1430 content_range='bytes 0-%s/*' % upto_bytes,
1431 content_type='application/octet-stream',
1432 source_object='/%s/%s' % (self.client.container, obj))
1434 @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1435 @patch('%s.object_post' % pithos_pkg, return_value=FR())
1436 def test_overwrite_object(self, post, GCI):
1438 tmpFile = self._create_temp_file(num_of_blocks)
1440 file_size = tmpFile.tell()
1441 info = dict(object_info)
1442 info['content-length'] = file_size
1443 block_size = container_info['x-container-block-size']
1445 PithosClient, 'get_object_info',
1446 return_value=info) as GOI:
1449 (file_size + 1, file_size + 2)):
1453 self.client.overwrite_object,
1454 obj, start, end, tmpFile)
1455 for start, end in ((0, 144), (144, 233), (233, file_size)):
1458 exp_size = end - start + 1
1459 if not start or exp_size > block_size:
1461 from progress.bar import ShadyBar
1462 owr_bar = ShadyBar('Mock append')
1469 for i in owr_bar.iter(range(n)):
1473 if exp_size > block_size:
1474 exp_size = exp_size % block_size or block_size
1476 self.client.overwrite_object(obj, start, end, tmpFile, owr_gen)
1477 self.assertEqual(GOI.mock_calls[-1], call(obj))
1478 self.assertEqual(GCI.mock_calls[-1], call())
1479 (args, kwargs) = post.mock_calls[-1][1:3]
1480 self.assertEqual(args, (obj,))
1481 self.assertEqual(len(kwargs['data']), exp_size)
1482 self.assertEqual(kwargs['content_length'], exp_size)
1483 self.assertEqual(kwargs['update'], True)
1484 exp = 'application/octet-stream'
1485 self.assertEqual(kwargs['content_type'], exp)
1487 @patch('%s.set_param' % pithos_pkg)
1488 @patch('%s.get' % pithos_pkg, return_value=FR())
1489 def test_get_sharing_accounts(self, get, SP):
1493 dict(limit='50m3-11m17'),
1495 dict(limit='50m3-11m17', marker='X')):
1496 r = self.client.get_sharing_accounts(**kws)
1497 self.assertEqual(get.mock_calls[-1], call('', success=(200, 204)))
1498 self.assertEqual(SP.mock_calls[-3], call('format', 'json'))
1499 limit, marker = kws.get('limit', None), kws.get('marker', None)
1500 self.assertEqual(SP.mock_calls[-2], call(
1502 iff=limit is not None))
1503 self.assertEqual(SP.mock_calls[-1], call(
1505 iff=marker is not None))
1506 for i in range(len(r)):
1507 self.assert_dicts_are_equal(r[i], sharers[i])
1509 @patch('%s.object_get' % pithos_pkg, return_value=FR())
1510 def test_get_object_versionlist(self, get):
1511 info = dict(object_info)
1512 info['versions'] = ['v1', 'v2']
1514 r = self.client.get_object_versionlist(obj)
1515 get.assert_called_once_with(obj, format='json', version='list')
1516 self.assertEqual(r, info['versions'])
1518 if __name__ == '__main__':
1519 from sys import argv
1520 from kamaki.clients.test import runTestCase
1522 if not argv[1:] or argv[1] == 'Pithos':
1524 runTestCase(Pithos, 'Pithos Client', argv[2:])
1525 if not argv[1:] or argv[1] == 'PithosRest':
1527 runTestCase(PithosRest, 'PithosRest Client', argv[2:])
1529 print('TestCase %s not found' % argv[1])