Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / test / pithos.py @ bcbf3cf0

History | View | Annotate | Download (9.3 kB)

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

    
34
from unittest import TestCase
35
from mock import patch, call, Mock
36

    
37
from kamaki.clients import ClientError
38
from kamaki.clients.pithos import PithosClient as PC
39
from kamaki.clients.astakos import AstakosClient
40
from kamaki.clients.connection.kamakicon import KamakiHTTPConnection as C
41

    
42
user_id = 'ac0un7-1d-5tr1ng'
43

    
44
account_info = {
45
    'content-language': 'en-us',
46
    'content-type': 'text/html; charset=utf-8',
47
    'date': 'Wed, 06 Mar 2013 13:25:51 GMT',
48
    'last-modified': 'Mon, 04 Mar 2013 18:22:31 GMT',
49
    'server': 'gunicorn/0.14.5',
50
    'vary': 'Accept-Language',
51
    'x-account-bytes-used': '751615526',
52
    'x-account-container-count': 7,
53
    'x-account-policy-quota': 53687091200,
54
    'x-account-policy-versioning': 'auto'}
55
container_info = {
56
    'content-language': 'en-us',
57
    'content-type': 'text/html; charset=utf-8',
58
    'date': 'Wed, 06 Mar 2013 15:11:05 GMT',
59
    'last-modified': 'Wed, 27 Feb 2013 15:56:13 GMT',
60
    'server': 'gunicorn/0.14.5',
61
    'vary': 'Accept-Language',
62
    'x-container-block-hash': 'sha256',
63
    'x-container-block-size': 4194304,
64
    'x-container-bytes-used': 309528938,
65
    'x-container-object-count': 14,
66
    'x-container-object-meta': '',
67
    'x-container-policy-quota': 53687091200,
68
    'x-container-policy-versioning': 'auto'}
69
container_list = [
70
    dict(
71
        count=2,
72
        last_modified="2013-02-27T11:56:09.893033+00:00",
73
        bytes=677076979,
74
        name="pithos",
75
        x_container_policy=dict(quota="21474836480", versioning="auto")),
76
    dict(
77
        count=0,
78
        last_modified="2012-10-23T12:25:17.229187+00:00",
79
        bytes=0,
80
        name="trash",
81
        x_container_policy=dict(quota="21474836480", versioning="auto"))]
82

    
83

    
84
class Pithos(TestCase):
85

    
86
    class FR(object):
87
        """FR stands for Fake Response"""
88
        json = dict()
89
        headers = dict()
90
        content = json
91
        status = None
92
        status_code = 200
93

    
94
        def release(self):
95
            pass
96

    
97
    files = []
98

    
99
    def assert_dicts_are_equal(self, d1, d2):
100
        for k, v in d1.items():
101
            self.assertTrue(k in d2)
102
            if isinstance(v, dict):
103
                self.assert_dicts_are_equal(v, d2[k])
104
            else:
105
                self.assertEqual(unicode(v), unicode(d2[k]))
106

    
107
    def setUp(self):
108
        self.url = 'https://www.example.com/pithos'
109
        self.token = 'p17h0570k3n'
110
        self.client = PC(self.url, self.token)
111
        self.client.account = user_id
112
        self.client.container = 'c0nt@1n3r_i'
113

    
114
    def tearDown(self):
115
        self.FR.headers = dict()
116
        self.FR.status_code = 200
117
        self.FR.json = dict()
118

    
119
    def test_get_account_info(self):
120
        self.FR.headers = account_info
121
        self.FR.status_code = 204
122
        with patch.object(C, 'perform_request', return_value=self.FR()):
123
            r = self.client.get_account_info()
124
            self.assertEqual(self.client.http_client.url, self.url)
125
            self.assertEqual(self.client.http_client.path, '/%s' % user_id)
126
            self.assert_dicts_are_equal(r, account_info)
127
            PC.set_param = Mock()
128
            untils = ['date 1', 'date 2', 'date 3']
129
            for unt in untils:
130
                r = self.client.get_account_info(until=unt)
131
                self.assert_dicts_are_equal(r, account_info)
132
            for i in range(len(untils)):
133
                self.assertEqual(
134
                    PC.set_param.mock_calls[i],
135
                    call('until', untils[i], iff=untils[i]))
136
            self.FR.status_code = 401
137
            self.assertRaises(ClientError, self.client.get_account_info)
138

    
139
    def test_replace_account_meta(self):
140
        self.FR.status_code = 202
141
        metas = dict(k1='v1', k2='v2', k3='v3')
142
        PC.set_header = Mock()
143
        with patch.object(C, 'perform_request', return_value=self.FR()):
144
            self.client.replace_account_meta(metas)
145
            self.assertEqual(self.client.http_client.url, self.url)
146
            self.assertEqual(self.client.http_client.path, '/%s' % user_id)
147
            prfx = 'X-Account-Meta-'
148
            expected = [call('%s%s' % (prfx, k), v) for k, v in metas.items()]
149
            self.assertEqual(PC.set_header.mock_calls, expected)
150

    
151
    def test_del_account_meta(self):
152
        keys = ['k1', 'k2', 'k3']
153
        with patch.object(PC, 'account_post', return_value=self.FR()) as ap:
154
            expected = []
155
            for key in keys:
156
                self.client.del_account_meta(key)
157
                expected.append(call(update=True, metadata={key: ''}))
158
            self.assertEqual(ap.mock_calls, expected)
159

    
160
    def test_create_container(self):
161
        self.FR.status_code = 201
162
        with patch.object(PC, 'put', return_value=self.FR()) as put:
163
            cont = 's0m3c0n731n3r'
164
            self.client.create_container(cont)
165
            expected = [call('/%s/%s' % (user_id, cont), success=(201, 202))]
166
            self.assertEqual(put.mock_calls, expected)
167
            self.FR.status_code = 202
168
            self.assertRaises(ClientError, self.client.create_container, cont)
169

    
170
    def test_get_container_info(self):
171
        self.FR.headers = container_info
172
        with patch.object(PC, 'container_head', return_value=self.FR()) as ch:
173
            r = self.client.get_container_info()
174
            self.assert_dicts_are_equal(r, container_info)
175
            u = 'some date'
176
            r = self.client.get_container_info(until=u)
177
            self.assertEqual(ch.mock_calls, [call(until=None), call(until=u)])
178

    
179
    def test_delete_container(self):
180
        self.FR.status_code = 204
181
        with patch.object(PC, 'delete', return_value=self.FR()) as delete:
182
            cont = 's0m3c0n731n3r'
183
            self.client.delete_container(cont)
184
            self.FR.status_code = 404
185
            self.assertRaises(ClientError, self.client.delete_container, cont)
186
            self.FR.status_code = 409
187
            self.assertRaises(ClientError, self.client.delete_container, cont)
188
            acall = call('/%s/%s' % (user_id, cont), success=(204, 404, 409))
189
            self.assertEqual(delete.mock_calls, [acall] * 3)
190

    
191
    def test_list_containers(self):
192
        self.FR.json = container_list
193
        with patch.object(PC, 'account_get', return_value=self.FR()):
194
            r = self.client.list_containers()
195
            for i in range(len(r)):
196
                self.assert_dicts_are_equal(r[i], container_list[i])
197

    
198
    def test_upload_object(self):
199
        PC.get_container_info = Mock(return_value=container_info)
200
        PC.container_post = Mock(return_value=self.FR())
201
        PC.object_put = Mock(return_value=self.FR())
202
        from tempfile import NamedTemporaryFile
203
        from os import urandom
204
        tmpFile = NamedTemporaryFile()
205
        num_of_blocks = 8
206
        file_size = num_of_blocks * 4 * 1024 * 1024
207
        print('\n\tCreate tmp file')
208
        tmpFile.write(urandom(file_size))
209
        tmpFile.flush()
210
        tmpFile.seek(0)
211
        print('\t\tDone')
212
        obj = 'objectName'
213
        self.client.upload_object(obj, tmpFile)
214
        tmpFile.close()
215
        self.assertEqual(PC.get_container_info.mock_calls, [call()])
216
        [call1, call2] = PC.object_put.mock_calls
217

    
218
        (args, kwargs) = call1[1:3]
219
        self.assertEqual(args, (obj,))
220
        expected = dict(
221
            hashmap=True,
222
            success=(201, 409),
223
            format='json',
224
            json=dict(
225
                hashes=['s0m3h@5h'] * num_of_blocks,
226
                bytes=file_size),
227
            etag=None,
228
            content_encoding=None,
229
            content_type='application/octet-stream',
230
            content_disposition=None,
231
            public=None,
232
            permissions=None)
233
        for k, v in expected.items():
234
            if k == 'json':
235
                self.assertEqual(len(v['hashes']), len(kwargs[k]['hashes']))
236
                self.assertEqual(v['bytes'], kwargs[k]['bytes'])
237
            else:
238
                self.assertEqual(v, kwargs[k])
239
        # TO BE CONTINUED
240
        (args, kwargs) = call2[1:3]