Fix all minor typos and modifications in tests
[kamaki] / kamaki / clients / pithos / test.py
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 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
40
41 try:
42     from collections import OrderedDict
43 except ImportError:
44     from kamaki.clients.utils.ordereddict import OrderedDict
45
46 from kamaki.clients import pithos, ClientError
47
48
49 rest_pkg = 'kamaki.clients.pithos.rest_api.PithosRestClient'
50 pithos_pkg = 'kamaki.clients.pithos.PithosClient'
51
52 user_id = 'ac0un7-1d-5tr1ng'
53 obj = 'obj3c7N4m3'
54
55 account_info = {
56     'content-language': 'en-us',
57     'content-type': 'text/html; charset=utf-8',
58     'date': 'Wed, 06 Mar 2013 13:25:51 GMT',
59     'last-modified': 'Mon, 04 Mar 2013 18:22:31 GMT',
60     'server': 'gunicorn/0.14.5',
61     'vary': 'Accept-Language',
62     'x-account-bytes-used': '751615526',
63     'x-account-container-count': 7,
64     'x-account-policy-quota': 53687091200,
65     'x-account-policy-versioning': 'auto'}
66 container_info = {
67     'content-language': 'en-us',
68     'content-type': 'text/html; charset=utf-8',
69     'date': 'Wed, 06 Mar 2013 15:11:05 GMT',
70     'last-modified': 'Wed, 27 Feb 2013 15:56:13 GMT',
71     'server': 'gunicorn/0.14.5',
72     'vary': 'Accept-Language',
73     'x-container-block-hash': 'sha256',
74     'x-container-block-size': 4194304,
75     'x-container-bytes-used': 309528938,
76     'x-container-object-count': 14,
77     'x-container-object-meta': '',
78     'x-container-policy-quota': 53687091200,
79     'x-container-policy-versioning': 'auto'}
80 object_info = {
81     'content-language': 'en-us',
82     'content-length': 254965,
83     'content-type': 'application/octet-stream',
84     'date': 'Thu, 07 Mar 2013 13:27:43 GMT',
85     'etag': '',
86     'last-modified': 'Mon, 04 Mar 2013 18:22:31 GMT',
87     'server': 'gunicorn/0.14.5',
88     'vary': 'Accept-Language',
89     'x-object-hash': 'obj3c7h45h1s0bj3c7h45h411r34dY',
90     'x-object-uuid': 'd0c747ca-34bd-49e0-8e98-1d07d8b0cbc7',
91     'x-object-version': '525996',
92     'x-object-version-timestamp': 'Mon, 04 Mar 2013 18:22:31 GMT',
93     'x-object-meta-k1': 'v1',
94     'x-object-meta-k2': 'v2'}
95 container_list = [
96     dict(
97         count=2,
98         last_modified="2013-02-27T11:56:09.893033+00:00",
99         bytes=677076979,
100         name="pithos",
101         x_container_policy=dict(quota="21474836480", versioning="auto")),
102     dict(
103         count=0,
104         last_modified="2012-10-23T12:25:17.229187+00:00",
105         bytes=0,
106         name="trash",
107         x_container_policy=dict(quota="21474836480", versioning="auto"))]
108 object_list = [
109     dict(hash="",
110         name="The_Secret_Garden.zip",
111         x_object_public="/public/wdp9p",
112         bytes=203304947,
113         x_object_version_timestamp="1360237915.7027509",
114         x_object_uuid="s0m3uu1df0r0bj0n3",
115         last_modified="2013-02-07T11:51:55.702751+00:00",
116         content_type="application/octet-stream",
117         x_object_hash="0afdf29f71cd53126225c3f54ca",
118         x_object_version=17737,
119         x_object_modified_by=user_id),
120     dict(hash="",
121         name="The_Revealed_Garden.zip",
122         x_object_public="/public/wpd7p",
123         bytes=20330947,
124         x_object_version_timestamp="13602915.7027509",
125         x_object_uuid="s0m3uu1df0r0bj70w",
126         last_modified="2013-02-07T11:51:55.702751+00:00",
127         content_type="application/octet-stream",
128         x_object_hash="0afdf29f71cd53126225c3f54ca",
129         x_object_version=17737,
130         x_object_modified_by=user_id)]
131 object_hashmap = dict(
132     block_hash="sha256", block_size=4194304, bytes=33554432,
133     hashes=[
134         "4988438cc1c0292c085d289649b28cf547ba3db71c6efaac9f2df7e193d4d0af",
135         "b214244aa56df7d1df7c6cac066e7cef268d9c2beb4dcf7ce68af667b0626f91",
136         "17f365f25e0682565ded30576066bb13377a3d306967e4d74e06bb6bbc20f75f",
137         "2524ae208932669fff89adf8a2fc0df3b67736ca0d3aadce7a2ce640f142af37",
138         "5d807a2129d2fcd3c221c3da418ed52af3fc48d0817b62e0bb437acffccd3514",
139         "609de22ce842d997f645fc49d5f14e0e3766dd51a6cbe66383b2bab82c8dfcd0",
140         "3102851ac168c78be70e35ff5178c7b1ebebd589e5106d565ca1094d1ca8ff59",
141         "bfe306dd24e92a8d85caf7055643f250fd319e8c4cdd4755ddabbf3ff97e83c7"])
142 sharers = [
143     dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="0b1a-82d5"),
144     dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="0b2a-f2d5"),
145     dict(last_modified="2013-01-29T16:50:06.084674+00:00", name="2b1a-82d6")]
146
147
148 class FR(object):
149     """FR stands for Fake Response"""
150     json = dict()
151     headers = dict()
152     content = json
153     status = None
154     status_code = 200
155
156
157 class PithosRestClient(TestCase):
158
159     def setUp(self):
160         self.url = 'https://www.example.com/pithos'
161         self.token = 'p17h0570k3n'
162         self.client = pithos.PithosRestClient(self.url, self.token)
163         self.client.account = user_id
164         self.client.container = 'c0nt@1n3r_i'
165
166     def tearDown(self):
167         FR.headers = dict()
168         FR.json = dict()
169         FR.content = FR.json
170
171     @patch('%s.set_param' % rest_pkg)
172     @patch('%s.set_header' % rest_pkg)
173     @patch('%s.head' % rest_pkg, return_value=FR())
174     def test_account_head(self, head, SH, SP):
175         for params in product(
176                 (None, '50m3-d473'),
177                 (None, '50m3-07h3r-d473'),
178                 (None, 'y37-4n7h3r-d473'),
179                 ((), ('someval',), ('v1', 'v2',)),
180                 (dict(), dict(success=200), dict(k='v', v='k'))):
181             args, kwargs = params[-2], params[-1]
182             params = params[:-2]
183             self.client.account_head(*(params + args), **kwargs)
184             unt = params[0]
185             self.assertEqual(SP.mock_calls[-1], call('until', unt, iff=unt))
186             IMS, IUS = params[1], params[2]
187             self.assertEqual(SH.mock_calls[-2:], [
188                 call('If-Modified-Since', IMS),
189                 call('If-Unmodified-Since', IUS)])
190             self.assertEqual(head.mock_calls[-1], call(
191                 '/%s' % self.client.account,
192                 *args,
193                 success=kwargs.pop('success', 204),
194                 **kwargs))
195
196     @patch('%s.set_param' % rest_pkg)
197     @patch('%s.set_header' % rest_pkg)
198     @patch('%s.get' % rest_pkg, return_value=FR())
199     def test_account_get(self, get, SH, SP):
200         keys = ('limit', 'marker', 'format', 'shared', 'until')
201         for params in product(
202                 (None, 42),
203                 (None, 'X'),
204                 ('json', 'xml'),
205                 (False, True),
206                 (None, '50m3-d473'),
207                 (None, '50m3-07h3r-d473'),
208                 (None, 'y37-4n7h3r-d473'),
209                 ((), ('someval',), ('v1', 'v2',)),
210                 (dict(), dict(success=200), dict(k='v', v='k'))):
211             args, kwargs = params[-2], params[-1]
212             params = params[:-2]
213             self.client.account_get(*(params + args), **kwargs)
214             self.assertEqual(SP.mock_calls[-5:],
215                 [call(keys[i], iff=X) if (
216                     i == 3) else call(
217                         keys[i], X, iff=X) for i, X in enumerate(params[:5])])
218             IMS, IUS = params[5], params[6]
219             self.assertEqual(SH.mock_calls[-2:], [
220                 call('If-Modified-Since', IMS),
221                 call('If-Unmodified-Since', IUS)])
222             self.assertEqual(get.mock_calls[-1], call(
223                 '/%s' % self.client.account,
224                 *args,
225                 success=kwargs.pop('success', (200, 204)),
226                 **kwargs))
227
228     @patch('%s.set_param' % rest_pkg)
229     @patch('%s.set_header' % rest_pkg)
230     @patch('%s.post' % rest_pkg, return_value=FR())
231     def test_account_post(self, post, SH, SP):
232         #keys = ('update', 'groups', 'metadata', 'quota', 'versioning')
233         for pm in product(
234                 (True, False),
235                 ({}, dict(g=['u1', 'u2']), dict(g1=[], g2=['u1', 'u2'])),
236                 (None, dict(k1='v1', k2='v2', k3='v2'), dict(k='v')),
237                 (None, 42),
238                 (None, 'v3r510n1ng'),
239                 ((), ('someval',), ('v1', 'v2',)),
240                 (dict(), dict(success=200), dict(k='v', v='k'))):
241             args, kwargs = pm[-2:]
242             pm = pm[:-2]
243             self.client.account_post(*(pm + args), **kwargs)
244             upd = pm[0]
245             self.assertEqual(SP.mock_calls[-1], call('update', iff=upd))
246             expected = []
247             if pm[1]:
248                 expected += [
249                 call('X-Account-Group-%s' % k, v) for k, v in pm[1].items()]
250             if pm[2]:
251                 expected = [
252                 call('X-Account-Meta-%s' % k, v) for k, v in pm[2].items()]
253             expected = [
254                 call('X-Account-Policy-Quota', pm[3]),
255                 call('X-Account-Policy-Versioning', pm[4])]
256             self.assertEqual(SH.mock_calls[- len(expected):], expected)
257             self.assertEqual(post.mock_calls[-1], call(
258                 '/%s' % self.client.account,
259                 *args,
260                 success=kwargs.pop('success', 202),
261                 **kwargs))
262
263     @patch('%s.set_param' % rest_pkg)
264     @patch('%s.set_header' % rest_pkg)
265     @patch('%s.head' % rest_pkg, return_value=FR())
266     def test_container_head(self, head, SH, SP):
267         for pm in product(
268                 (None, '4-d473'),
269                 (None, '47h3r-d473'),
270                 (None, 'y37-4n47h3r'),
271                 ((), ('someval',)),
272                 (dict(), dict(success=200), dict(k='v', v='k'))):
273             args, kwargs = pm[-2:]
274             pm = pm[:-2]
275             self.client.container_head(*(pm + args), **kwargs)
276             unt, ims, ius = pm[0:3]
277             self.assertEqual(SP.mock_calls[-1], call('until', unt, iff=unt))
278             self.assertEqual(SH.mock_calls[-2:], [
279                 call('If-Modified-Since', ims),
280                 call('If-Unmodified-Since', ius)])
281             self.assertEqual(head.mock_calls[-1], call(
282                 '/%s/%s' % (self.client.account, self.client.container),
283                 *args,
284                 success=kwargs.pop('success', 204),
285                 **kwargs))
286
287     @patch('%s.set_param' % rest_pkg)
288     @patch('%s.set_header' % rest_pkg)
289     @patch('%s.get' % rest_pkg, return_value=FR())
290     def test_container_get(self, get, SH, SP):
291         for pm in product(
292                 (None, 42),
293                 (None, 'X'),
294                 (None, 'some/prefix'),
295                 (None, 'delimiter'),
296                 (None, '/some/path'),
297                 ('json', 'some-format'),
298                 ([], ['k1', 'k2', 'k3']),
299                 (False, True),
300                 (None, 'unt1l-d473'),
301                 (None, 'y37-4n47h3r'),
302                 (None, '4n47h3r-d473'),
303                 ((), ('someval',)),
304                 (dict(), dict(success=400), dict(k='v', v='k'))):
305             args, kwargs = pm[-2:]
306             pm = pm[:-2]
307             self.client.container_get(*(pm + args), **kwargs)
308             lmt, mrk, prfx, dlm, path, frmt, meta, shr, unt = pm[:-2]
309             exp = [call('limit', lmt, iff=lmt), call('marker', mrk, iff=mrk)]
310             exp += [call('path', path)] if path else [
311                 call('prefix', prfx, iff=prfx),
312                 call('delimiter', dlm, iff=dlm)]
313             exp += [call('format', frmt, iff=frmt), call('shared', iff=shr)]
314             if meta:
315                 exp += [call('meta', ','.join(meta))]
316             exp += [call('until', unt, iff=unt)]
317             self.assertEqual(SP.mock_calls[- len(exp):], exp)
318             ims, ius = pm[-2:]
319             self.assertEqual(SH.mock_calls[-2:], [
320                 call('If-Modified-Since', ims),
321                 call('If-Unmodified-Since', ius)])
322             self.assertEqual(get.mock_calls[-1], call(
323                 '/%s/%s' % (self.client.account, self.client.container),
324                 *args,
325                 success=kwargs.pop('success', 200),
326                 **kwargs))
327
328     @patch('%s.set_header' % rest_pkg)
329     @patch('%s.put' % rest_pkg, return_value=FR())
330     def test_container_put(self, put, SH):
331         for pm in product(
332                 (None, 42),
333                 (None, 'v3r51on1ng'),
334                 (dict(), dict(k1='v2'), dict(k2='v2', k3='v3')),
335                 ((), ('someval',)),
336                 (dict(), dict(success=400), dict(k='v', v='k'))):
337             args, kwargs = pm[-2:]
338             pm = pm[:-2]
339             self.client.container_put(*(pm + args), **kwargs)
340             quota, versioning, metas = pm[-3:]
341             exp = [
342                 call('X-Container-Policy-Quota', quota),
343                 call('X-Container-Policy-Versioning', versioning)] + [
344                 call('X-Container-Meta-%s' % k, v) for k, v in metas.items()]
345             self.assertEqual(SH.mock_calls[- len(exp):], exp)
346             self.assertEqual(put.mock_calls[-1], call(
347                 '/%s/%s' % (self.client.account, self.client.container),
348                 *args,
349                 success=kwargs.pop('success', (201, 202)),
350                 **kwargs))
351
352     @patch('%s.set_param' % rest_pkg)
353     @patch('%s.set_header' % rest_pkg)
354     @patch('%s.post' % rest_pkg, return_value=FR())
355     def test_container_post(self, post, SH, SP):
356         for pm in product(
357                 (True, False),
358                 ('json', 'some-format'),
359                 (None, 'quota'),
360                 (None, 'v3r51on1ng'),
361                 (dict(), dict(k1='v2'), dict(k2='v2', k3='v3')),
362                 (None, 'content-type'),
363                 (None, 42),
364                 (None, 'transfer-encoding'),
365                 ((), ('someval',)),
366                 (dict(), dict(success=400), dict(k='v', v='k'))):
367             args, kwargs = pm[-2:]
368             pm = pm[:-2]
369             self.client.container_post(*(pm + args), **kwargs)
370             upd, frmt = pm[:2]
371             self.assertEqual(SP.mock_calls[-2:], [
372                 call('update', iff=upd),
373                 call('format', frmt, iff=frmt)])
374             qta, vrs, metas, ctype, clen, trenc = pm[2:]
375             prfx = 'X-Container-Meta-'
376             exp = [
377                 call('X-Container-Policy-Quota', qta),
378                 call('X-Container-Policy-Versioning', vrs)] + [
379                 call('%s%s' % (prfx, k), v) for k, v in metas.items()] + [
380                 call('Content-Type', ctype),
381                 call('Content-Length', clen),
382                 call('Transfer-Encoding', trenc)]
383             self.assertEqual(SH.mock_calls[- len(exp):], exp)
384             ims, ius = pm[-2:]
385             self.assertEqual(post.mock_calls[-1], call(
386                 '/%s/%s' % (self.client.account, self.client.container),
387                 *args,
388                 success=kwargs.pop('success', 202),
389                 **kwargs))
390
391     @patch('%s.set_param' % rest_pkg)
392     @patch('%s.delete' % rest_pkg, return_value=FR())
393     def test_container_delete(self, delete, SP):
394         for pm in product(
395                 (None, 'd473'),
396                 (None, 'd3l1m'),
397                 ((), ('someval',)),
398                 (dict(), dict(success=400), dict(k='v', v='k'))):
399             args, kwargs = pm[-2:]
400             pm = pm[:-2]
401             self.client.container_delete(*(pm + args), **kwargs)
402             unt, dlm = pm[-2:]
403             self.assertEqual(SP.mock_calls[-2:], [
404                 call('until', unt, iff=unt),
405                 call('delimiter', dlm, iff=dlm)])
406             self.assertEqual(delete.mock_calls[-1], call(
407                 '/%s/%s' % (self.client.account, self.client.container),
408                 *args,
409                 success=kwargs.pop('success', 204),
410                 **kwargs))
411
412     @patch('%s.set_param' % rest_pkg)
413     @patch('%s.set_header' % rest_pkg)
414     @patch('%s.head' % rest_pkg, return_value=FR())
415     def test_object_head(self, head, SH, SP):
416         for pm in product(
417                 (None, 'v3r510n'),
418                 (None, '1f-374g'),
419                 (None, '1f-n0-74g'),
420                 (None, '1f-m0d-51nc3'),
421                 (None, '1f-unm0d-51nc3'),
422                 ((), ('someval',)),
423                 (dict(), dict(success=400), dict(k='v', v='k'))):
424             args, kwargs = pm[-2:]
425             pm = pm[:-2]
426             self.client.object_head(obj, *(pm + args), **kwargs)
427             vrs, etag, netag, ims, ius = pm[:5]
428             self.assertEqual(
429                 SP.mock_calls[-1],
430                 call('version', vrs, iff=vrs))
431             self.assertEqual(SH.mock_calls[-4:], [
432                 call('If-Match', etag),
433                 call('If-None-Match', netag),
434                 call('If-Modified-Since', ims),
435                 call('If-Unmodified-Since', ius)])
436             acc, cont = self.client.account, self.client.container
437             self.assertEqual(head.mock_calls[-1], call(
438                 '/%s/%s/%s' % (acc, cont, obj),
439                 *args,
440                 success=kwargs.pop('success', 200),
441                 **kwargs))
442
443     @patch('%s.set_param' % rest_pkg)
444     @patch('%s.set_header' % rest_pkg)
445     @patch('%s.get' % rest_pkg, return_value=FR())
446     def test_object_get(self, get, SH, SP):
447         for pm in product(
448                 ('json', 'f0rm47'),
449                 (False, True),
450                 (None, 'v3r510n'),
451                 (None, 'range=74-63'),
452                 (False, True),
453                 (None, '3746'),
454                 (None, 'non-3746'),
455                 (None, '1f-m0d'),
456                 (None, '1f-unm0d'),
457                 ((), ('someval',)),
458                 (dict(), dict(success=400), dict(k='v', v='k'))):
459             args, kwargs = pm[-2:]
460             pm = pm[:-2]
461             self.client.object_get(obj, *(pm + args), **kwargs)
462             format, hashmap, version = pm[:3]
463             self.assertEqual(SP.mock_calls[-3:], [
464                 call('format', format, iff=format),
465                 call('hashmap', hashmap, iff=hashmap),
466                 call('version', version, iff=version)])
467             rng, ifrng, im, inm, ims, ius = pm[-6:]
468             self.assertEqual(SH.mock_calls[-6:], [
469                 call('Range', rng),
470                 call('If-Range', '', ifrng and rng),
471                 call('If-Match', im),
472                 call('If-None-Match', inm),
473                 call('If-Modified-Since', ims),
474                 call('If-Unmodified-Since', ius)])
475             acc, cont = self.client.account, self.client.container
476             self.assertEqual(get.mock_calls[-1], call(
477                 '/%s/%s/%s' % (acc, cont, obj),
478                 *args,
479                 success=kwargs.pop('success', 200),
480                 **kwargs))
481
482     @patch('%s.set_param' % rest_pkg)
483     @patch('%s.set_header' % rest_pkg)
484     @patch('%s.put' % rest_pkg, return_value=FR())
485     def test_object_put(self, put, SH, SP):
486         for pm in product(
487                 ('json', 'f0rm47'),
488                 (False, True),
489                 (None, 'delim',),
490                 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
491                 (False, True),
492                 (dict(), dict(k2='v2', k3='v3')),
493                 ((), ('someval',)),
494                 (dict(), dict(success=400), dict(k='v', v='k'))):
495             args, kwargs = pm[-2:]
496             pm = pm[:-2]
497             terms = [None] * 13
498             for i in range(len(terms)):
499                 if randint(0, 2):
500                     terms[i] = 'val_%s' % randint(13, 1024)
501             self.client.object_put(
502                 obj,
503                 *(pm[:3] + tuple(terms) + pm[3:] + args),
504                 **kwargs)
505             format, hashmap, delimiter = pm[:3]
506             self.assertEqual(SP.mock_calls[-3:], [
507                 call('format', format, iff=format),
508                 call('hashmap', hashmap, iff=hashmap),
509                 call('delimiter', delimiter, iff=delimiter)])
510             (
511                 im, inm, etag, clen, ctype, trenc,
512                 cp, mv, srcacc, srcvrs, conenc, condis, mnf) = terms
513             perms, public, metas = pm[3:]
514             exp = [
515                 call('If-Match', im),
516                 call('If-None-Match', inm),
517                 call('ETag', etag),
518                 call('Content-Length', clen),
519                 call('Content-Type', ctype),
520                 call('Transfer-Encoding', trenc),
521                 call('X-Copy-From', cp),
522                 call('X-Move-From', mv),
523                 call('X-Source-Account', srcacc),
524                 call('X-Source-Version', srcvrs),
525                 call('Content-Encoding', conenc),
526                 call('Content-Disposition', condis),
527                 call('X-Object-Manifest', mnf)]
528             if perms:
529                 perm_str = ''
530                 for ptype, pval in perms.items():
531                     if pval:
532                         perm_str += ';' if perm_str else ''
533                         perm_str += '%s=%s' % (ptype, ','.join(pval))
534                 exp += [call('X-Object-Sharing', perm_str)]
535             exp += [call('X-Object-Public', public, public is not None)]
536             for k, v in metas.items():
537                 exp += [call('X-Object-Meta-%s' % k, v)]
538             self.assertEqual(SH.mock_calls[- len(exp):], exp)
539             acc, cont = self.client.account, self.client.container
540             self.assertEqual(put.mock_calls[-1], call(
541                 '/%s/%s/%s' % (acc, cont, obj),
542                 *args,
543                 success=kwargs.pop('success', 201),
544                 **kwargs))
545
546     @patch('%s.set_param' % rest_pkg)
547     @patch('%s.set_header' % rest_pkg)
548     @patch('%s.copy' % rest_pkg, return_value=FR())
549     def test_object_copy(self, copy, SH, SP):
550         dest = 'dest1n4710n'
551         for pm in product(
552                 ('json', 'f0rm47'),
553                 (False, True),
554                 (None, 'ifmatch'),
555                 (None, 'ifnonematch'),
556                 (None, 'destinationaccount'),
557                 (None, 'content-type'),
558                 (None, 'content-encoding'),
559                 (None, 'content-disp'),
560                 (None, 'source-version'),
561                 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
562                 (False, True),
563                 (dict(), dict(k2='v2', k3='v3')),
564                 ((), ('someval',)),
565                 (dict(), dict(success=400), dict(k='v', v='k'))):
566             args, kwargs = pm[-2:]
567             pm = pm[:-2]
568             self.client.object_copy(obj, dest, *(pm + args), **kwargs)
569             format, ict = pm[:2]
570             self.assertEqual(SP.mock_calls[-2:], [
571                 call('format', format, iff=format),
572                 call('ignore_content_type', iff=ict)])
573             im, inm, da, ct, ce, cd, sv, perms, public, metas = pm[2:]
574             exp = [call('If-Match', im),
575                 call('If-None-Match', inm),
576                 call('Destination', dest),
577                 call('Destination-Account', da),
578                 call('Content-Type', ct),
579                 call('Content-Encoding', ce),
580                 call('Content-Disposition', cd),
581                 call('X-Source-Version', sv)]
582             if perms:
583                 perm_str = ''
584                 for ptype, pval in perms.items():
585                     if pval:
586                         perm_str += ';' if perm_str else ''
587                         perm_str += '%s=%s' % (ptype, ','.join(pval))
588                 exp += [call('X-Object-Sharing', perm_str)]
589             exp += [call('X-Object-Public', public, public is not None)]
590             for k, v in metas.items():
591                 exp += [call('X-Object-Meta-%s' % k, v)]
592             self.assertEqual(SH.mock_calls[- len(exp):], exp)
593             acc, cont = self.client.account, self.client.container
594             self.assertEqual(copy.mock_calls[-1], call(
595                 '/%s/%s/%s' % (acc, cont, obj),
596                 *args,
597                 success=kwargs.pop('success', 201),
598                 **kwargs))
599
600     @patch('%s.set_param' % rest_pkg)
601     @patch('%s.set_header' % rest_pkg)
602     @patch('%s.move' % rest_pkg, return_value=FR())
603     def test_object_move(self, move, SH, SP):
604         for pm in product(
605                 ('json', 'f0rm47'),
606                 (False, True),
607                 (None, 'ifmatch'),
608                 (None, 'ifnonematch'),
609                 (None, 'destination'),
610                 (None, 'destinationaccount'),
611                 (None, 'content-type'),
612                 (None, 'content-encoding'),
613                 (None, 'content-disp'),
614                 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
615                 (False, True),
616                 (dict(), dict(k2='v2', k3='v3')),
617                 ((), ('someval',)),
618                 (dict(), dict(success=400), dict(k='v', v='k'))):
619             args, kwargs = pm[-2:]
620             pm = pm[:-2]
621             self.client.object_move(obj, *(pm + args), **kwargs)
622             format, ict = pm[:2]
623             self.assertEqual(SP.mock_calls[-2:], [
624                 call('format', format, iff=format),
625                 call('ignore_content_type', iff=ict)])
626             im, inm, d, da, ct, ce, cd, perms, public, metas = pm[2:]
627             exp = [call('If-Match', im),
628                 call('If-None-Match', inm),
629                 call('Destination', d),
630                 call('Destination-Account', da),
631                 call('Content-Type', ct),
632                 call('Content-Encoding', ce),
633                 call('Content-Disposition', cd)]
634             if perms:
635                 perm_str = ''
636                 for ptype, pval in perms.items():
637                     if pval:
638                         perm_str += ';' if perm_str else ''
639                         perm_str += '%s=%s' % (ptype, ','.join(pval))
640                 exp += [call('X-Object-Sharing', perm_str)]
641             exp += [call('X-Object-Public', public, public is not None)]
642             for k, v in metas.items():
643                 exp += [call('X-Object-Meta-%s' % k, v)]
644             self.assertEqual(SH.mock_calls[- len(exp):], exp)
645             acc, cont = self.client.account, self.client.container
646             self.assertEqual(move.mock_calls[-1], call(
647                 '/%s/%s/%s' % (acc, cont, obj),
648                 *args,
649                 success=kwargs.pop('success', 201),
650                 **kwargs))
651
652     @patch('%s.set_param' % rest_pkg)
653     @patch('%s.set_header' % rest_pkg)
654     @patch('%s.post' % rest_pkg, return_value=FR())
655     def test_object_post(self, post, SH, SP):
656         for pm in product(
657                 ('json', 'f0rm47'),
658                 (False, True),
659                 (dict(), dict(read=['u1', 'g2'], write=['u1'])),
660                 (False, True),
661                 (dict(), dict(k2='v2', k3='v3')),
662                 ((), ('someval',)),
663                 (dict(), dict(success=400), dict(k='v', v='k'))):
664             args, kwargs = pm[-2:]
665             pm = pm[:-2]
666             terms = [None] * 13
667             for i in range(len(terms)):
668                 if randint(0, 2):
669                     terms[i] = 'val_%s' % randint(13, 1024)
670             self.client.object_post(
671                 obj,
672                 *(pm[:2] + tuple(terms) + pm[2:] + args),
673                 **kwargs)
674             format, update = pm[:2]
675             self.assertEqual(SP.mock_calls[-2:], [
676                 call('format', format, iff=format),
677                 call('update', iff=update)])
678             (
679                 im, inm, clen, ctype, crng, trenc, cenc,
680                 condis, srcobj, srcacc, srcvrs, obytes, mnfs) = terms
681             exp = [
682                 call('If-Match', im),
683                 call('If-None-Match', inm),
684                 call('Content-Length', clen, iff=not trenc),
685                 call('Content-Type', ctype),
686                 call('Content-Range', crng),
687                 call('Transfer-Encoding', trenc),
688                 call('Content-Encoding', cenc),
689                 call('Content-Disposition', condis),
690                 call('X-Source-Object', srcobj),
691                 call('X-Source-Account', srcacc),
692                 call('X-Source-Version', srcvrs),
693                 call('X-Object-Bytes', obytes),
694                 call('X-Object-Manifest', mnfs)]
695             perms, public, metas = pm[2:]
696             if perms:
697                 perm_str = ''
698                 for ptype, pval in perms.items():
699                     if pval:
700                         perm_str += ';' if perm_str else ''
701                         perm_str += '%s=%s' % (ptype, ','.join(pval))
702                 exp += [call('X-Object-Sharing', perm_str)]
703             exp += [call('X-Object-Public', public, public is not None)]
704             for k, v in metas.items():
705                 exp += [call('X-Object-Meta-%s' % k, v)]
706             self.assertEqual(SH.mock_calls[- len(exp):], exp)
707             acc, cont = self.client.account, self.client.container
708             self.assertEqual(post.mock_calls[-1], call(
709                 '/%s/%s/%s' % (acc, cont, obj),
710                 *args,
711                 success=kwargs.pop('success', (202, 204)),
712                 **kwargs))
713
714     @patch('%s.set_param' % rest_pkg)
715     @patch('%s.delete' % rest_pkg, return_value=FR())
716     def test_object_delete(self, delete, SP):
717         for pm in product(
718                 (None, 'until'),
719                 (None, 'delim'),
720                 ((), ('someval',)),
721                 (dict(), dict(success=400), dict(k='v', v='k'))):
722             args, kwargs = pm[-2:]
723             pm = pm[:-2]
724             self.client.object_delete(
725                 obj,
726                 *(pm + args),
727                 **kwargs)
728             until, dlm = pm[-2:]
729             self.assertEqual(SP.mock_calls[-2:], [
730                 call('until', until, iff=until),
731                 call('delimiter', dlm, iff=dlm)])
732             acc, cont = self.client.account, self.client.container
733             self.assertEqual(delete.mock_calls[-1], call(
734                 '/%s/%s/%s' % (acc, cont, obj),
735                 *args,
736                 success=kwargs.pop('success', 204),
737                 **kwargs))
738
739
740 class PithosClient(TestCase):
741
742     files = []
743
744     def _create_temp_file(self, num_of_blocks):
745         self.files.append(NamedTemporaryFile())
746         tmpFile = self.files[-1]
747         file_size = num_of_blocks * 4 * 1024 * 1024
748         print('\n\tCreate tmp file')
749         tmpFile.write(urandom(file_size))
750         tmpFile.flush()
751         tmpFile.seek(0)
752         print('\t\tDone')
753         return tmpFile
754
755     def assert_dicts_are_equal(self, d1, d2):
756         for k, v in d1.items():
757             self.assertTrue(k in d2)
758             if isinstance(v, dict):
759                 self.assert_dicts_are_equal(v, d2[k])
760             else:
761                 self.assertEqual(unicode(v), unicode(d2[k]))
762
763     def setUp(self):
764         self.url = 'https://www.example.com/pithos'
765         self.token = 'p17h0570k3n'
766         self.client = pithos.PithosClient(self.url, self.token)
767         self.client.account = user_id
768         self.client.container = 'c0nt@1n3r_i'
769
770     def tearDown(self):
771         FR.headers = dict()
772         FR.status_code = 200
773         FR.json = dict()
774         FR.content = FR.json
775         for f in self.files:
776             f.close()
777
778     #  Pithos+ methods that extend storage API
779
780     @patch('%s.account_head' % pithos_pkg, return_value=FR())
781     def test_get_account_info(self, AH):
782         FR.headers = account_info
783         for until in (None, 'un71L-d473'):
784             r = self.client.get_account_info(until=until)
785             self.assert_dicts_are_equal(r, account_info)
786             self.assertEqual(AH.mock_calls[-1], call(until=until))
787         FR.status_code = 401
788         self.assertRaises(ClientError, self.client.get_account_info)
789
790     @patch('%s.account_post' % pithos_pkg, return_value=FR())
791     def test_del_account_meta(self, AP):
792         keys = ['k1', 'k2', 'k3']
793         for key in keys:
794             self.client.del_account_meta(key)
795             self.assertEqual(
796                 AP.mock_calls[-1],
797                 call(update=True, metadata={key: ''}))
798
799     @patch('%s.container_head' % pithos_pkg, return_value=FR())
800     def test_get_container_info(self, CH):
801         FR.headers = container_info
802         r = self.client.get_container_info()
803         self.assert_dicts_are_equal(r, container_info)
804         u = 'some date'
805         r = self.client.get_container_info(until=u)
806         self.assertEqual(CH.mock_calls, [call(until=None), call(until=u)])
807
808     @patch('%s.account_get' % pithos_pkg, return_value=FR())
809     def test_list_containers(self, get):
810         FR.json = container_list
811         r = self.client.list_containers()
812         get.assert_called_once_with()
813         for i in range(len(r)):
814             self.assert_dicts_are_equal(r[i], container_list[i])
815
816     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
817     @patch('%s.container_post' % pithos_pkg, return_value=FR())
818     @patch('%s.object_put' % pithos_pkg, return_value=FR())
819     def test_upload_object(self, OP, CP, GCI):
820         num_of_blocks = 8
821         tmpFile = self._create_temp_file(num_of_blocks)
822
823         # Without kwargs
824         exp_headers = dict(id='container id', name='container name')
825         FR.headers = dict(exp_headers)
826         r = self.client.upload_object(obj, tmpFile)
827         self.assert_dicts_are_equal(r, exp_headers)
828         self.assertEqual(GCI.mock_calls[-1], call())
829
830         [call1, call2] = OP.mock_calls
831         (args1, kwargs1) = call1[1:3]
832         (args2, kwargs2) = call2[1:3]
833         self.assertEqual(args1, (obj,))
834         expected1 = dict(
835             hashmap=True,
836             success=(201, 409),
837             format='json',
838             json=dict(
839                 hashes=['s0m3h@5h'] * num_of_blocks,
840                 bytes=num_of_blocks * 4 * 1024 * 1024),
841             content_encoding=None,
842             content_type='application/octet-stream',
843             content_disposition=None,
844             public=None,
845             permissions=None)
846         for k, v in expected1.items():
847             if k == 'json':
848                 self.assertEqual(len(v['hashes']), len(kwargs1[k]['hashes']))
849                 self.assertEqual(v['bytes'], kwargs1[k]['bytes'])
850             else:
851                 self.assertEqual(v, kwargs1[k])
852
853         (args2, kwargs2) = call2[1:3]
854         self.assertEqual(args2, (obj,))
855         expected2 = dict(
856             json=dict(
857                 hashes=['s0m3h@5h'] * num_of_blocks,
858                 bytes=num_of_blocks * 4 * 1024 * 1024),
859             content_type='application/octet-stream',
860             hashmap=True,
861             success=201,
862             format='json')
863         for k, v in expected2.items():
864             if k == 'json':
865                 self.assertEqual(len(v['hashes']), len(kwargs2[k]['hashes']))
866                 self.assertEqual(v['bytes'], kwargs2[k]['bytes'])
867             else:
868                 self.assertEqual(v, kwargs2[k])
869
870         mock_offset = 2
871
872         #  With progress bars
873         try:
874             from progress.bar import ShadyBar
875             blck_bar = ShadyBar('Mock blck calc.')
876             upld_bar = ShadyBar('Mock uplds')
877         except ImportError:
878             blck_bar = None
879             upld_bar = None
880
881         if blck_bar and upld_bar:
882
883             def blck_gen(n):
884                 for i in blck_bar.iter(range(n)):
885                     yield
886                 yield
887
888             def upld_gen(n):
889                 for i in upld_bar.iter(range(n)):
890                     yield
891                 yield
892
893             tmpFile.seek(0)
894             r = self.client.upload_object(
895                 obj, tmpFile,
896                 hash_cb=blck_gen, upload_cb=upld_gen)
897             self.assert_dicts_are_equal(r, exp_headers)
898
899             for i, c in enumerate(OP.mock_calls[-mock_offset:]):
900                 self.assertEqual(OP.mock_calls[i], c)
901
902         #  With content-type
903         tmpFile.seek(0)
904         ctype = 'video/mpeg'
905         sharing = dict(read=['u1', 'g1', 'u2'], write=['u1'])
906         r = self.client.upload_object(obj, tmpFile,
907             content_type=ctype, sharing=sharing)
908         self.assert_dicts_are_equal(r, exp_headers)
909         self.assertEqual(OP.mock_calls[-1][2]['content_type'], ctype)
910         self.assert_dicts_are_equal(
911             OP.mock_calls[-2][2]['permissions'],
912             sharing)
913
914         # With other args
915         tmpFile.seek(0)
916         kwargs = dict(
917             etag='s0m3E74g',
918             if_etag_match='if etag match',
919             if_not_exist=True,
920             content_type=ctype,
921             content_disposition=ctype + 'd15p051710n',
922             public=True,
923             content_encoding='802.11',
924             container_info_cache={})
925         r = self.client.upload_object(obj, tmpFile, **kwargs)
926         self.assert_dicts_are_equal(r, exp_headers)
927
928         kwargs.pop('if_not_exist')
929         ematch = kwargs.pop('if_etag_match')
930         etag = kwargs.pop('etag')
931         self.assert_dicts_are_equal(
932             kwargs.pop('container_info_cache'),
933             {self.client.container: container_info})
934         for arg, val in kwargs.items():
935             self.assertEqual(OP.mock_calls[-2][2][arg], val)
936         self.assertEqual(OP.mock_calls[-1][2]['if_etag_match'], ematch)
937         self.assertEqual(OP.mock_calls[-1][2]['if_etag_not_match'], '*')
938         self.assertEqual(OP.mock_calls[-1][2]['etag'], etag)
939
940     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
941     @patch('%s.container_post' % pithos_pkg, return_value=FR())
942     @patch('%s.object_put' % pithos_pkg, return_value=FR())
943     def test_upload_from_string(self, OP, CP, GCI):
944         num_of_blocks = 2
945         tmpFile = self._create_temp_file(num_of_blocks)
946         tmpFile.seek(0)
947         src_str = tmpFile.read()
948
949         exp_headers = dict(id='container id', name='container name')
950         FR.headers = dict(exp_headers)
951         r = self.client.upload_from_string(obj, src_str)
952         self.assert_dicts_are_equal(r, exp_headers)
953         self.assertEqual(GCI.mock_calls[-1], call())
954
955         [call1, call2] = OP.mock_calls
956         (args1, kwargs1) = call1[1:3]
957         (args2, kwargs2) = call2[1:3]
958         self.assertEqual(args1, (obj,))
959         expected1 = dict(
960             hashmap=True,
961             success=(201, 409),
962             format='json',
963             json=dict(
964                 hashes=['s0m3h@5h'] * num_of_blocks,
965                 bytes=num_of_blocks * 4 * 1024 * 1024),
966             content_encoding=None,
967             content_type='application/octet-stream',
968             content_disposition=None,
969             public=None,
970             permissions=None)
971         for k, v in expected1.items():
972             if k == 'json':
973                 self.assertEqual(len(v['hashes']), len(kwargs1[k]['hashes']))
974                 self.assertEqual(v['bytes'], kwargs1[k]['bytes'])
975             else:
976                 self.assertEqual(v, kwargs1[k])
977
978         (args2, kwargs2) = call2[1:3]
979         self.assertEqual(args2, (obj,))
980         expected2 = dict(
981             json=dict(
982                 hashes=['s0m3h@5h'] * num_of_blocks,
983                 bytes=num_of_blocks * 4 * 1024 * 1024),
984             content_type='application/octet-stream',
985             hashmap=True,
986             success=201,
987             format='json')
988         for k, v in expected2.items():
989             if k == 'json':
990                 self.assertEqual(len(v['hashes']), len(kwargs2[k]['hashes']))
991                 self.assertEqual(v['bytes'], kwargs2[k]['bytes'])
992             else:
993                 self.assertEqual(v, kwargs2[k])
994
995         mock_offset = 2
996
997         #  With progress bars
998         try:
999             from progress.bar import ShadyBar
1000             blck_bar = ShadyBar('Mock blck calc.')
1001             upld_bar = ShadyBar('Mock uplds')
1002         except ImportError:
1003             blck_bar = None
1004             upld_bar = None
1005
1006         if blck_bar and upld_bar:
1007
1008             def blck_gen(n):
1009                 for i in blck_bar.iter(range(n)):
1010                     yield
1011                 yield
1012
1013             def upld_gen(n):
1014                 for i in upld_bar.iter(range(n)):
1015                     yield
1016                 yield
1017
1018             tmpFile.seek(0)
1019             r = self.client.upload_object(
1020                 obj, tmpFile,
1021                 hash_cb=blck_gen, upload_cb=upld_gen)
1022             self.assert_dicts_are_equal(r, exp_headers)
1023
1024             for i, c in enumerate(OP.mock_calls[-mock_offset:]):
1025                 self.assertEqual(OP.mock_calls[i], c)
1026
1027         #  With content-type
1028         tmpFile.seek(0)
1029         ctype = 'video/mpeg'
1030         sharing = dict(read=['u1', 'g1', 'u2'], write=['u1'])
1031         r = self.client.upload_object(obj, tmpFile,
1032             content_type=ctype, sharing=sharing)
1033         self.assert_dicts_are_equal(r, exp_headers)
1034         self.assertEqual(OP.mock_calls[-1][2]['content_type'], ctype)
1035         self.assert_dicts_are_equal(
1036             OP.mock_calls[-2][2]['permissions'],
1037             sharing)
1038
1039         # With other args
1040         tmpFile.seek(0)
1041         kwargs = dict(
1042             etag='s0m3E74g',
1043             if_etag_match='if etag match',
1044             if_not_exist=True,
1045             content_type=ctype,
1046             content_disposition=ctype + 'd15p051710n',
1047             public=True,
1048             content_encoding='802.11',
1049             container_info_cache={})
1050         r = self.client.upload_object(obj, tmpFile, **kwargs)
1051         self.assert_dicts_are_equal(r, exp_headers)
1052
1053         kwargs.pop('if_not_exist')
1054         ematch = kwargs.pop('if_etag_match')
1055         etag = kwargs.pop('etag')
1056         self.assert_dicts_are_equal(
1057             kwargs.pop('container_info_cache'),
1058             {self.client.container: container_info})
1059         for arg, val in kwargs.items():
1060             self.assertEqual(OP.mock_calls[-2][2][arg], val)
1061         self.assertEqual(OP.mock_calls[-1][2]['if_etag_match'], ematch)
1062         self.assertEqual(OP.mock_calls[-1][2]['if_etag_not_match'], '*')
1063         self.assertEqual(OP.mock_calls[-1][2]['etag'], etag)
1064
1065     def test_get_object_info(self):
1066         FR.headers = object_info
1067         version = 'v3r510n'
1068         with patch.object(
1069                 pithos.PithosClient, 'object_head',
1070                 return_value=FR()) as head:
1071             r = self.client.get_object_info(obj)
1072             self.assertEqual(r, object_info)
1073             r = self.client.get_object_info(obj, version=version)
1074             self.assertEqual(head.mock_calls, [
1075                 call(obj, version=None),
1076                 call(obj, version=version)])
1077         with patch.object(
1078                 pithos.PithosClient, 'object_head',
1079                 side_effect=ClientError('Obj not found', 404)):
1080             self.assertRaises(
1081                 ClientError,
1082                 self.client.get_object_info,
1083                 obj, version=version)
1084
1085     @patch('%s.get_object_info' % pithos_pkg, return_value=object_info)
1086     def test_get_object_meta(self, GOI):
1087         for version in (None, 'v3r510n'):
1088             r = self.client.get_object_meta(obj, version)
1089             for k in [k for k in object_info if k.startswith('x-object-meta')]:
1090                 self.assertEqual(r.pop(k), object_info[k])
1091             self.assertFalse(len(r))
1092             self.assertEqual(GOI.mock_calls[-1], call(obj, version=version))
1093
1094     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1095     def test_del_object_meta(self, post):
1096         metakey = '50m3m3t4k3y'
1097         self.client.del_object_meta(obj, metakey)
1098         post.assert_called_once_with(obj, update=True, metadata={metakey: ''})
1099
1100     @patch('%s.object_put' % pithos_pkg, return_value=FR())
1101     def test_copy_object(self, put):
1102         src_cont = 'src-c0nt41n3r'
1103         src_obj = 'src-0bj'
1104         dst_cont = 'dst-c0nt41n3r'
1105         dst_obj = 'dst-0bj'
1106         expected = call(
1107             src_obj,
1108             content_length=0,
1109             source_account=None,
1110             success=201,
1111             copy_from='/%s/%s' % (src_cont, src_obj),
1112             delimiter=None,
1113             content_type=None,
1114             source_version=None,
1115             public=False)
1116         self.client.copy_object(src_cont, src_obj, dst_cont)
1117         self.assertEqual(put.mock_calls[-1], expected)
1118         self.client.copy_object(src_cont, src_obj, dst_cont, dst_obj)
1119         self.assertEqual(put.mock_calls[-1][1], (dst_obj,))
1120         kwargs = dict(
1121             source_version='src-v3r510n',
1122             source_account='src-4cc0un7',
1123             public=True,
1124             content_type='c0n73n7Typ3',
1125             delimiter='5')
1126         self.client.copy_object(src_cont, src_obj, dst_cont, **kwargs)
1127         for k, v in kwargs.items():
1128             self.assertEqual(v, put.mock_calls[-1][2][k])
1129
1130     @patch('%s.object_put' % pithos_pkg, return_value=FR())
1131     def test_move_object(self, put):
1132         src_cont = 'src-c0nt41n3r'
1133         src_obj = 'src-0bj'
1134         dst_cont = 'dst-c0nt41n3r'
1135         dst_obj = 'dst-0bj'
1136         expected = call(
1137             src_obj,
1138             content_length=0,
1139             source_account=None,
1140             success=201,
1141             move_from='/%s/%s' % (src_cont, src_obj),
1142             delimiter=None,
1143             content_type=None,
1144             source_version=None,
1145             public=False)
1146         self.client.move_object(src_cont, src_obj, dst_cont)
1147         self.assertEqual(put.mock_calls[-1], expected)
1148         self.client.move_object(src_cont, src_obj, dst_cont, dst_obj)
1149         self.assertEqual(put.mock_calls[-1][1], (dst_obj,))
1150         kwargs = dict(
1151             source_version='src-v3r510n',
1152             source_account='src-4cc0un7',
1153             public=True,
1154             content_type='c0n73n7Typ3',
1155             delimiter='5')
1156         self.client.move_object(src_cont, src_obj, dst_cont, **kwargs)
1157         for k, v in kwargs.items():
1158             self.assertEqual(v, put.mock_calls[-1][2][k])
1159
1160     #  Pithos+ only methods
1161
1162     @patch('%s.container_put' % pithos_pkg, return_value=FR())
1163     def test_create_container(self, CP):
1164         FR.headers = container_info
1165         cont = 'an0th3r_c0n741n3r'
1166
1167         r = self.client.create_container()
1168         self.assert_dicts_are_equal(r, container_info)
1169         CP.assert_called_once_with(quota=None, versioning=None, metadata=None)
1170
1171         bu_cont = self.client.container
1172         r = self.client.create_container(cont)
1173         self.assertEqual(self.client.container, bu_cont)
1174         self.assert_dicts_are_equal(r, container_info)
1175         self.assertEqual(
1176             CP.mock_calls[-1],
1177             call(quota=None, versioning=None, metadata=None))
1178
1179         meta = dict(k1='v1', k2='v2')
1180         r = self.client.create_container(cont, 42, 'auto', meta)
1181         self.assertEqual(self.client.container, bu_cont)
1182         self.assert_dicts_are_equal(r, container_info)
1183         self.assertEqual(
1184             CP.mock_calls[-1],
1185             call(quota=42, versioning='auto', metadata=meta))
1186
1187     @patch('%s.container_delete' % pithos_pkg, return_value=FR())
1188     def test_purge_container(self, CD):
1189         self.client.purge_container()
1190         self.assertTrue('until' in CD.mock_calls[-1][2])
1191         cont = self.client.container
1192         self.client.purge_container('another-container')
1193         self.assertEqual(self.client.container, cont)
1194
1195     @patch('%s.object_put' % pithos_pkg, return_value=FR())
1196     def test_upload_object_unchunked(self, put):
1197         num_of_blocks = 8
1198         tmpFile = self._create_temp_file(num_of_blocks)
1199         expected = dict(
1200                 success=201,
1201                 data=num_of_blocks * 4 * 1024 * 1024,
1202                 etag='some-etag',
1203                 content_encoding='some content_encoding',
1204                 content_type='some content-type',
1205                 content_disposition='some content_disposition',
1206                 public=True,
1207                 permissions=dict(read=['u1', 'g1', 'u2'], write=['u1']))
1208         r = self.client.upload_object_unchunked(obj, tmpFile)
1209         self.assert_dicts_are_equal(r, FR.headers)
1210         self.assertEqual(put.mock_calls[-1][1], (obj,))
1211         self.assertEqual(
1212             sorted(put.mock_calls[-1][2].keys()),
1213             sorted(expected.keys()))
1214         kwargs = dict(expected)
1215         kwargs.pop('success')
1216         kwargs['size'] = kwargs.pop('data')
1217         kwargs['sharing'] = kwargs.pop('permissions')
1218         tmpFile.seek(0)
1219         r = self.client.upload_object_unchunked(obj, tmpFile, **kwargs)
1220         self.assert_dicts_are_equal(r, FR.headers)
1221         pmc = put.mock_calls[-1][2]
1222         for k, v in expected.items():
1223             if k == 'data':
1224                 self.assertEqual(len(pmc[k]), v)
1225             else:
1226                 self.assertEqual(pmc[k], v)
1227         self.assertRaises(
1228             ClientError,
1229             self.client.upload_object_unchunked,
1230             obj, tmpFile, withHashFile=True)
1231
1232     @patch('%s.object_put' % pithos_pkg, return_value=FR())
1233     def test_create_object_by_manifestation(self, put):
1234         manifest = '%s/%s' % (self.client.container, obj)
1235         kwargs = dict(
1236                 etag='some-etag',
1237                 content_encoding='some content_encoding',
1238                 content_type='some content-type',
1239                 content_disposition='some content_disposition',
1240                 public=True,
1241                 sharing=dict(read=['u1', 'g1', 'u2'], write=['u1']))
1242         r = self.client.create_object_by_manifestation(obj)
1243         self.assert_dicts_are_equal(r, FR.headers)
1244         expected = dict(content_length=0, manifest=manifest)
1245         for k in kwargs:
1246             expected['permissions' if k == 'sharing' else k] = None
1247         self.assertEqual(put.mock_calls[-1], call(obj, **expected))
1248         r = self.client.create_object_by_manifestation(obj, **kwargs)
1249         self.assert_dicts_are_equal(r, FR.headers)
1250         expected.update(kwargs)
1251         expected['permissions'] = expected.pop('sharing')
1252         self.assertEqual(put.mock_calls[-1], call(obj, **expected))
1253
1254     @patch('%s.get_object_hashmap' % pithos_pkg, return_value=object_hashmap)
1255     @patch('%s.object_get' % pithos_pkg, return_value=FR())
1256     def test_download_to_string(self, GET, GOH):
1257         FR.content = 'some sample content'
1258         num_of_blocks = len(object_hashmap['hashes'])
1259         r = self.client.download_to_string(obj)
1260         expected_content = FR.content * num_of_blocks
1261         self.assertEqual(expected_content, r)
1262         self.assertEqual(len(GET.mock_calls), num_of_blocks)
1263         self.assertEqual(GET.mock_calls[-1][1], (obj,))
1264
1265         kwargs = dict(
1266             version='version',
1267             range_str='10-20',
1268             if_match='if and only if',
1269             if_none_match='if and only not',
1270             if_modified_since='what if not?',
1271             if_unmodified_since='this happens if not!')
1272         expargs = dict(kwargs)
1273         expargs.pop('range_str')
1274         for k in expargs:
1275             expargs[k] = None
1276         GOH.assert_called_once_with(obj, **expargs)
1277
1278         r = self.client.download_to_string(obj, **kwargs)
1279         expargs['data_range'] = 'bytes=%s' % kwargs['range_str']
1280         for k, v in expargs.items():
1281             self.assertEqual(
1282                 GET.mock_calls[-1][2][k],
1283                 v or kwargs.get(k))
1284
1285     @patch('%s.get_object_hashmap' % pithos_pkg, return_value=object_hashmap)
1286     @patch('%s.object_get' % pithos_pkg, return_value=FR())
1287     def test_download_object(self, GET, GOH):
1288         num_of_blocks = 8
1289         tmpFile = self._create_temp_file(num_of_blocks)
1290         FR.content = tmpFile.read(4 * 1024 * 1024)
1291         tmpFile = self._create_temp_file(num_of_blocks)
1292         num_of_blocks = len(object_hashmap['hashes'])
1293         kwargs = dict(
1294             resume=True,
1295             version='version',
1296             range_str='10-20',
1297             if_match='if and only if',
1298             if_none_match='if and only not',
1299             if_modified_since='what if not?',
1300             if_unmodified_since='this happens if not!',
1301             async_headers=dict(Range='bytes=0-88888888'))
1302
1303         self.client.download_object(obj, tmpFile)
1304         self.assertEqual(len(GET.mock_calls), num_of_blocks)
1305         self.assertEqual(GET.mock_calls[-1][1], (obj,))
1306         for k, v in kwargs.items():
1307             if k == 'async_headers':
1308                 self.assertTrue('Range' in GET.mock_calls[-1][2][k])
1309             elif k in ('resume', 'range_str'):
1310                 continue
1311             else:
1312                 self.assertEqual(GET.mock_calls[-1][2][k], None)
1313
1314         #  Check ranges are consecutive
1315         starts = []
1316         ends = []
1317         for c in GET.mock_calls:
1318             rng_str = c[2]['async_headers']['Range']
1319             (start, rng_str) = rng_str.split('=')
1320             (start, end) = rng_str.split('-')
1321             starts.append(start)
1322             ends.append(end)
1323         ends = sorted(ends)
1324         for i, start in enumerate(sorted(starts)):
1325             if i:
1326                 int(ends[i - 1]) == int(start) - 1
1327
1328         #  With progress bars
1329         try:
1330             from progress.bar import ShadyBar
1331             dl_bar = ShadyBar('Mock dl')
1332         except ImportError:
1333             dl_bar = None
1334
1335         if dl_bar:
1336
1337             def blck_gen(n):
1338                 for i in dl_bar.iter(range(n)):
1339                     yield
1340                 yield
1341
1342             tmpFile.seek(0)
1343             self.client.download_object(obj, tmpFile, download_cb=blck_gen)
1344             self.assertEqual(len(GET.mock_calls), 2 * num_of_blocks)
1345
1346         tmpFile.seek(0)
1347         kwargs.pop('async_headers')
1348         kwargs.pop('resume')
1349         self.client.download_object(obj, tmpFile, **kwargs)
1350         for k, v in kwargs.items():
1351             if k == 'range_str':
1352                 self.assertEqual(
1353                     GET.mock_calls[-1][2]['data_range'],
1354                     'bytes=%s' % v)
1355             else:
1356                 self.assertEqual(GET.mock_calls[-1][2][k], v)
1357
1358         #  ALl options on no tty
1359         def foo():
1360             return True
1361
1362         tmpFile.seek(0)
1363         tmpFile.isatty = foo
1364         self.client.download_object(obj, tmpFile, **kwargs)
1365         for k, v in kwargs.items():
1366             if k == 'range_str':
1367                 self.assertTrue('data_range' in GET.mock_calls[-1][2])
1368             else:
1369                 self.assertEqual(GET.mock_calls[-1][2][k], v)
1370
1371     def test_get_object_hashmap(self):
1372         FR.json = object_hashmap
1373         for empty in (304, 412):
1374             with patch.object(
1375                     pithos.PithosClient, 'object_get',
1376                     side_effect=ClientError('Empty', status=empty)):
1377                 r = self.client.get_object_hashmap(obj)
1378                 self.assertEqual(r, {})
1379         exp_args = dict(
1380             hashmap=True,
1381             data_range=None,
1382             version=None,
1383             if_etag_match=None,
1384             if_etag_not_match=None,
1385             if_modified_since=None,
1386             if_unmodified_since=None)
1387         kwargs = dict(
1388             version='s0m3v3r51on',
1389             if_match='if match',
1390             if_none_match='if non match',
1391             if_modified_since='some date here',
1392             if_unmodified_since='some date here',
1393             data_range='10-20')
1394         with patch.object(
1395                 pithos.PithosClient, 'object_get',
1396                 return_value=FR()) as get:
1397             r = self.client.get_object_hashmap(obj)
1398             self.assertEqual(r, object_hashmap)
1399             self.assertEqual(get.mock_calls[-1], call(obj, **exp_args))
1400             r = self.client.get_object_hashmap(obj, **kwargs)
1401             exp_args['if_etag_match'] = kwargs.pop('if_match')
1402             exp_args['if_etag_not_match'] = kwargs.pop('if_none_match')
1403             exp_args.update(kwargs)
1404             self.assertEqual(get.mock_calls[-1], call(obj, **exp_args))
1405
1406     @patch('%s.account_post' % pithos_pkg, return_value=FR())
1407     def test_set_account_group(self, post):
1408         (group, usernames) = ('aU53rGr0up', ['u1', 'u2', 'u3'])
1409         self.client.set_account_group(group, usernames)
1410         post.assert_called_once_with(update=True, groups={group: usernames})
1411
1412     @patch('%s.account_post' % pithos_pkg, return_value=FR())
1413     def test_del_account_group(self, post):
1414         group = 'aU53rGr0up'
1415         self.client.del_account_group(group)
1416         post.assert_called_once_with(update=True, groups={group: []})
1417
1418     @patch('%s.get_account_info' % pithos_pkg, return_value=account_info)
1419     def test_get_account_quota(self, GAI):
1420         key = 'x-account-policy-quota'
1421         r = self.client.get_account_quota()
1422         GAI.assert_called_once_with()
1423         self.assertEqual(r[key], account_info[key])
1424
1425     @patch('%s.get_account_info' % pithos_pkg, return_value=account_info)
1426     def test_get_account_versioning(self, GAI):
1427         key = 'x-account-policy-versioning'
1428         r = self.client.get_account_versioning()
1429         GAI.assert_called_once_with()
1430         self.assertEqual(r[key], account_info[key])
1431
1432     def test_get_account_meta(self):
1433         key = 'x-account-meta-'
1434         with patch.object(
1435                 pithos.PithosClient, 'get_account_info',
1436                 return_value=account_info):
1437             r = self.client.get_account_meta()
1438             keys = [k for k in r if k.startswith(key)]
1439             self.assertFalse(keys)
1440         acc_info = dict(account_info)
1441         acc_info['%sk1' % key] = 'v1'
1442         acc_info['%sk2' % key] = 'v2'
1443         acc_info['%sk3' % key] = 'v3'
1444         with patch.object(
1445                 pithos.PithosClient, 'get_account_info',
1446                 return_value=acc_info):
1447             r = self.client.get_account_meta()
1448             for k in [k for k in acc_info if k.startswith(key)]:
1449                 self.assertEqual(r[k], acc_info[k])
1450
1451     def test_get_account_group(self):
1452         key = 'x-account-group-'
1453         with patch.object(
1454                 pithos.PithosClient, 'get_account_info',
1455                 return_value=account_info):
1456             r = self.client.get_account_group()
1457             keys = [k for k in r if k.startswith(key)]
1458             self.assertFalse(keys)
1459         acc_info = dict(account_info)
1460         acc_info['%sk1' % key] = 'g1'
1461         acc_info['%sk2' % key] = 'g2'
1462         acc_info['%sk3' % key] = 'g3'
1463         with patch.object(
1464                 pithos.PithosClient, 'get_account_info',
1465                 return_value=acc_info):
1466             r = self.client.get_account_group()
1467             for k in [k for k in acc_info if k.startswith(key)]:
1468                 self.assertEqual(r[k], acc_info[k])
1469
1470     @patch('%s.account_post' % pithos_pkg, return_value=FR())
1471     def test_set_account_meta(self, post):
1472         metas = dict(k1='v1', k2='v2', k3='v3')
1473         self.client.set_account_meta(metas)
1474         post.assert_called_once_with(update=True, metadata=metas)
1475
1476     """
1477     @patch('%s.account_post' % pithos_pkg, return_value=FR())
1478     def test_set_account_quota(self, post):
1479         qu = 1024
1480         self.client.set_account_quota(qu)
1481         post.assert_called_once_with(update=True, quota=qu)
1482     """
1483
1484     @patch('%s.account_post' % pithos_pkg, return_value=FR())
1485     def test_set_account_versioning(self, post):
1486         vrs = 'n3wV3r51on1ngTyp3'
1487         self.client.set_account_versioning(vrs)
1488         post.assert_called_once_with(update=True, versioning=vrs)
1489
1490     @patch('%s.container_delete' % pithos_pkg, return_value=FR())
1491     def test_del_container(self, delete):
1492         for kwarg in (
1493                 dict(delimiter=None, until=None),
1494                 dict(delimiter='X', until='50m3d473')):
1495             self.client.del_container(**kwarg)
1496             expected = dict(kwarg)
1497             expected['success'] = (204, 404, 409)
1498             self.assertEqual(delete.mock_calls[-1], call(**expected))
1499         for status_code in (404, 409):
1500             FR.status_code = status_code
1501             self.assertRaises(ClientError, self.client.del_container)
1502
1503     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1504     def test_get_container_versioning(self, GCI):
1505         key = 'x-container-policy-versioning'
1506         cont = 'c0n7-417'
1507         bu_cnt = self.client.container
1508         for container in (None, cont):
1509             r = self.client.get_container_versioning(container=container)
1510             self.assertEqual(r[key], container_info[key])
1511             self.assertEqual(GCI.mock_calls[-1], call())
1512             self.assertEqual(bu_cnt, self.client.container)
1513
1514     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1515     def test_get_container_limit(self, GCI):
1516         key = 'x-container-policy-quota'
1517         cont = 'c0n7-417'
1518         bu_cnt = self.client.container
1519         for container in (None, cont):
1520             r = self.client.get_container_limit(container=container)
1521             self.assertEqual(r[key], container_info[key])
1522             self.assertEqual(GCI.mock_calls[-1], call())
1523             self.assertEqual(bu_cnt, self.client.container)
1524
1525     def test_get_container_meta(self):
1526         somedate = '50m3d473'
1527         key = 'x-container-meta'
1528         metaval = '50m3m374v41'
1529         container_plus = dict(container_info)
1530         container_plus[key] = metaval
1531         for ret in ((container_info, {}), (container_plus, {key: metaval})):
1532             with patch.object(
1533                     pithos.PithosClient,
1534                     'get_container_info',
1535                     return_value=ret[0]) as GCI:
1536                 for until in (None, somedate):
1537                     r = self.client.get_container_meta(until=until)
1538                     self.assertEqual(r, ret[1])
1539                     self.assertEqual(GCI.mock_calls[-1], call(until=until))
1540
1541     def test_get_container_object_meta(self):
1542         somedate = '50m3d473'
1543         key = 'x-container-object-meta'
1544         metaval = '50m3m374v41'
1545         container_plus = dict(container_info)
1546         container_plus[key] = metaval
1547         for ret in (
1548                 (container_info, {key: ''}),
1549                 (container_plus, {key: metaval})):
1550             with patch.object(
1551                     pithos.PithosClient,
1552                     'get_container_info',
1553                     return_value=ret[0]) as GCI:
1554                 for until in (None, somedate):
1555                     r = self.client.get_container_object_meta(until=until)
1556                     self.assertEqual(r, ret[1])
1557                     self.assertEqual(GCI.mock_calls[-1], call(until=until))
1558
1559     @patch('%s.container_post' % pithos_pkg, return_value=FR())
1560     def test_set_container_meta(self, post):
1561         metas = dict(k1='v1', k2='v2', k3='v3')
1562         self.client.set_container_meta(metas)
1563         post.assert_called_once_with(update=True, metadata=metas)
1564
1565     @patch('%s.container_post' % pithos_pkg, return_value=FR())
1566     def test_del_container_meta(self, AP):
1567         self.client.del_container_meta('somekey')
1568         AP.assert_called_once_with(update=True, metadata={'somekey': ''})
1569
1570     @patch('%s.container_post' % pithos_pkg, return_value=FR())
1571     def test_set_container_limit(self, post):
1572         qu = 1024
1573         self.client.set_container_limit(qu)
1574         post.assert_called_once_with(update=True, quota=qu)
1575
1576     @patch('%s.container_post' % pithos_pkg, return_value=FR())
1577     def test_set_container_versioning(self, post):
1578         vrs = 'n3wV3r51on1ngTyp3'
1579         self.client.set_container_versioning(vrs)
1580         post.assert_called_once_with(update=True, versioning=vrs)
1581
1582     @patch('%s.object_delete' % pithos_pkg, return_value=FR())
1583     def test_del_object(self, delete):
1584         for kwarg in (
1585                 dict(delimiter=None, until=None),
1586                 dict(delimiter='X', until='50m3d473')):
1587             self.client.del_object(obj, **kwarg)
1588             self.assertEqual(delete.mock_calls[-1], call(obj, **kwarg))
1589
1590     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1591     def test_set_object_meta(self, post):
1592         metas = dict(k1='v1', k2='v2', k3='v3')
1593         self.assertRaises(
1594             AssertionError,
1595             self.client.set_object_meta,
1596             obj, 'Non dict arg')
1597         self.client.set_object_meta(obj, metas)
1598         post.assert_called_once_with(obj, update=True, metadata=metas)
1599
1600     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1601     def test_publish_object(self, post):
1602         oinfo = dict(object_info)
1603         val = 'pubL1c'
1604         oinfo['x-object-public'] = val
1605         with patch.object(
1606                 pithos.PithosClient, 'get_object_info',
1607                 return_value=oinfo) as GOF:
1608             r = self.client.publish_object(obj)
1609             self.assertEqual(
1610                 post.mock_calls[-1],
1611                 call(obj, public=True, update=True))
1612             self.assertEqual(GOF.mock_calls[-1], call(obj))
1613             self.assertEqual(r, '%s%s' % (self.url[:-6], val))
1614
1615     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1616     def test_unpublish_object(self, post):
1617         self.client.unpublish_object(obj)
1618         post.assert_called_once_with(obj, public=False, update=True)
1619
1620     def test_get_object_sharing(self):
1621         info = dict(object_info)
1622         expected = dict(read='u1,g1,u2', write='u1')
1623         info['x-object-sharing'] = '; '.join(
1624             ['%s=%s' % (k, v) for k, v in expected.items()])
1625         with patch.object(
1626                 pithos.PithosClient, 'get_object_info',
1627                 return_value=info) as GOF:
1628             r = self.client.get_object_sharing(obj)
1629             self.assertEqual(GOF.mock_calls[-1], call(obj))
1630             self.assert_dicts_are_equal(r, expected)
1631             info['x-object-sharing'] = '//'.join(
1632                 ['%s=%s' % (k, v) for k, v in expected.items()])
1633             self.assertRaises(
1634                 ValueError,
1635                 self.client.get_object_sharing,
1636                 obj)
1637             info['x-object-sharing'] = '; '.join(
1638                 ['%s:%s' % (k, v) for k, v in expected.items()])
1639             self.assertRaises(
1640                 ClientError,
1641                 self.client.get_object_sharing,
1642                 obj)
1643             info['x-object-sharing'] = 'read=%s' % expected['read']
1644             r = self.client.get_object_sharing(obj)
1645             expected.pop('write')
1646             self.assert_dicts_are_equal(r, expected)
1647
1648     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1649     def test_set_object_sharing(self, OP):
1650         read_perms = ['u1', 'g1', 'u2', 'g2']
1651         write_perms = ['u1', 'g1']
1652         for kwargs in (
1653                 dict(read_permission=read_perms, write_permission=write_perms),
1654                 dict(read_permission=read_perms),
1655                 dict(write_permission=write_perms),
1656                 dict()):
1657             self.client.set_object_sharing(obj, **kwargs)
1658             kwargs['read'] = kwargs.pop('read_permission', '')
1659             kwargs['write'] = kwargs.pop('write_permission', '')
1660             self.assertEqual(
1661                 OP.mock_calls[-1],
1662                 call(obj, update=True, permissions=kwargs))
1663
1664     @patch('%s.set_object_sharing' % pithos_pkg)
1665     def test_del_object_sharing(self, SOS):
1666         self.client.del_object_sharing(obj)
1667         SOS.assert_called_once_with(obj)
1668
1669     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1670     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1671     def test_append_object(self, post, GCI):
1672         num_of_blocks = 4
1673         tmpFile = self._create_temp_file(num_of_blocks)
1674         tmpFile.seek(0, 2)
1675         file_size = tmpFile.tell()
1676         for turn in range(2):
1677             tmpFile.seek(0, 0)
1678
1679             try:
1680                 from progress.bar import ShadyBar
1681                 apn_bar = ShadyBar('Mock append')
1682             except ImportError:
1683                 apn_bar = None
1684
1685             if apn_bar:
1686
1687                 def append_gen(n):
1688                     for i in apn_bar.iter(range(n)):
1689                         yield
1690                     yield
1691
1692             else:
1693                 append_gen = None
1694
1695             self.client.append_object(
1696                 obj, tmpFile,
1697                 upload_cb=append_gen if turn else None)
1698             self.assertEqual((turn + 1) * num_of_blocks, len(post.mock_calls))
1699             (args, kwargs) = post.mock_calls[-1][1:3]
1700             self.assertEqual(kwargs['obj'], obj)
1701             self.assertEqual(kwargs['content_length'], len(kwargs['data']))
1702             fsize = num_of_blocks * int(kwargs['content_length'])
1703             self.assertEqual(fsize, file_size)
1704             self.assertEqual(kwargs['content_range'], 'bytes */*')
1705             exp = 'application/octet-stream'
1706             self.assertEqual(kwargs['content_type'], exp)
1707             self.assertEqual(kwargs['update'], True)
1708
1709     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1710     def test_truncate_object(self, post):
1711         upto_bytes = 377
1712         self.client.truncate_object(obj, upto_bytes)
1713         post.assert_called_once_with(
1714             obj,
1715             update=True,
1716             object_bytes=upto_bytes,
1717             content_range='bytes 0-%s/*' % upto_bytes,
1718             content_type='application/octet-stream',
1719             source_object='/%s/%s' % (self.client.container, obj))
1720
1721     @patch('%s.get_container_info' % pithos_pkg, return_value=container_info)
1722     @patch('%s.object_post' % pithos_pkg, return_value=FR())
1723     def test_overwrite_object(self, post, GCI):
1724         num_of_blocks = 4
1725         tmpFile = self._create_temp_file(num_of_blocks)
1726         tmpFile.seek(0, 2)
1727         file_size = tmpFile.tell()
1728         info = dict(object_info)
1729         info['content-length'] = file_size
1730         block_size = container_info['x-container-block-size']
1731         with patch.object(
1732                 pithos.PithosClient, 'get_object_info',
1733                 return_value=info) as GOI:
1734             for start, end in (
1735                     (0, file_size + 1),
1736                     (file_size + 1, file_size + 2)):
1737                 tmpFile.seek(0, 0)
1738                 self.assertRaises(
1739                     ClientError,
1740                     self.client.overwrite_object,
1741                     obj, start, end, tmpFile)
1742             for start, end in ((0, 144), (144, 233), (233, file_size)):
1743                 tmpFile.seek(0, 0)
1744                 owr_gen = None
1745                 exp_size = end - start + 1
1746                 if not start or exp_size > block_size:
1747                     try:
1748                         from progress.bar import ShadyBar
1749                         owr_bar = ShadyBar('Mock append')
1750                     except ImportError:
1751                         owr_bar = None
1752
1753                     if owr_bar:
1754
1755                         def owr_gen(n):
1756                             for i in owr_bar.iter(range(n)):
1757                                 yield
1758                             yield
1759
1760                     if exp_size > block_size:
1761                         exp_size = exp_size % block_size or block_size
1762
1763                 self.client.overwrite_object(obj, start, end, tmpFile, owr_gen)
1764                 self.assertEqual(GOI.mock_calls[-1], call(obj))
1765                 self.assertEqual(GCI.mock_calls[-1], call())
1766                 (args, kwargs) = post.mock_calls[-1][1:3]
1767                 self.assertEqual(args, (obj,))
1768                 self.assertEqual(len(kwargs['data']), exp_size)
1769                 self.assertEqual(kwargs['content_length'], exp_size)
1770                 self.assertEqual(kwargs['update'], True)
1771                 exp = 'application/octet-stream'
1772                 self.assertEqual(kwargs['content_type'], exp)
1773
1774     @patch('%s.set_param' % pithos_pkg)
1775     @patch('%s.get' % pithos_pkg, return_value=FR())
1776     def test_get_sharing_accounts(self, get, SP):
1777         FR.json = sharers
1778         for kws in (
1779                 dict(),
1780                 dict(limit='50m3-11m17'),
1781                 dict(marker='X'),
1782                 dict(limit='50m3-11m17', marker='X')):
1783             r = self.client.get_sharing_accounts(**kws)
1784             self.assertEqual(get.mock_calls[-1], call('', success=(200, 204)))
1785             self.assertEqual(SP.mock_calls[-3], call('format', 'json'))
1786             limit, marker = kws.get('limit', None), kws.get('marker', None)
1787             self.assertEqual(SP.mock_calls[-2], call(
1788                 'limit', limit,
1789                 iff=limit is not None))
1790             self.assertEqual(SP.mock_calls[-1], call(
1791                 'marker', marker,
1792                 iff=marker is not None))
1793             for i in range(len(r)):
1794                 self.assert_dicts_are_equal(r[i], sharers[i])
1795
1796     @patch('%s.object_get' % pithos_pkg, return_value=FR())
1797     def test_get_object_versionlist(self, get):
1798         info = dict(object_info)
1799         info['versions'] = ['v1', 'v2']
1800         FR.json = info
1801         r = self.client.get_object_versionlist(obj)
1802         get.assert_called_once_with(obj, format='json', version='list')
1803         self.assertEqual(r, info['versions'])
1804
1805 if __name__ == '__main__':
1806     from sys import argv
1807     from kamaki.clients.test import runTestCase
1808     not_found = True
1809     if not argv[1:] or argv[1] == 'PithosClient':
1810         not_found = False
1811         runTestCase(PithosClient, 'Pithos Client', argv[2:])
1812     if not argv[1:] or argv[1] == 'PithosRestClient':
1813         not_found = False
1814         runTestCase(PithosRestClient, 'PithosRest Client', argv[2:])
1815     if not_found:
1816         print('TestCase %s not found' % argv[1])