Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / test / image.py @ de27950a

History | View | Annotate | Download (13.1 kB)

1
# Copyright 2012-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 mock import patch
35
from unittest import TestCase
36

    
37
from kamaki.clients import ClientError
38

    
39
example_images = [
40
    {
41
        "status": "available",
42
        "name": "Archlinux",
43
        "disk_format": "diskdump",
44
        "container_format": "bare",
45
        "id": "b4713f20-3a41-4eaf-81ae-88698c18b3e8",
46
        "size": 752782848},
47
    {
48
        "status": "available",
49
        "name": "maelstrom",
50
        "disk_format": "diskdump",
51
        "container_format": "bare",
52
        "id": "0fb03e45-7d5a-4515-bd4e-e6bbf6457f06",
53
        "size": 2583195644},
54
    {
55
        "status": "available",
56
        "name": "Gardenia",
57
        "disk_format": "diskdump",
58
        "container_format": "bare",
59
        "id": "5963020b-ab74-4e11-bc59-90c494bbdedb",
60
        "size": 2589802496}]
61

    
62
example_images_detailed = [
63
    {
64
        "status": "available",
65
        "name": "Archlinux",
66
        "checksum": "1a126aad07475b43cc1959b446344211be13974",
67
        "created_at": "2013-01-28 22:44:54",
68
        "disk_format": "diskdump",
69
        "updated_at": "2013-01-28 22:44:55",
70
        "properties": {
71
            "partition_table": "msdos",
72
            "osfamily": "linux",
73
            "users": "root",
74
            "exclude_task_assignhostname": "yes",
75
            "os": "archlinux",
76
            "root_partition": "1",
77
            "description": "Archlinux base install 2012.12.01"},
78
        "location": "pithos://us3r-I6E-1d/images/archlinux.12.2012",
79
        "container_format": "bare",
80
        "owner": "user163@mail.example.com",
81
        "is_public": True,
82
        "deleted_at": "",
83
        "id": "b4713f20-3a41-4eaf-81ae-88698c18b3e8",
84
        "size": 752782848},
85
    {
86
        "status": "available",
87
        "name": "maelstrom",
88
        "checksum": "b202b8c7030cb22f896c6664ac",
89
        "created_at": "2013-02-13 10:07:42",
90
        "disk_format": "diskdump",
91
        "updated_at": "2013-02-13 10:07:44",
92
        "properties": {
93
            "partition_table": "msdos",
94
            "osfamily": "linux",
95
            "description": "Ubuntu 12.04.1 LTS",
96
            "os": "ubuntu",
97
            "root_partition": "1",
98
            "users": "user"},
99
        "location": "pithos://us3r-@r3n@-1d/images/mls-201302131203.diskdump",
100
        "container_format": "bare",
101
        "owner": "user3@mail.example.com",
102
        "is_public": True,
103
        "deleted_at": "",
104
        "id": "0fb03e45-7d5a-4515-bd4e-e6bbf6457f06",
105
        "size": 2583195648},
106
    {
107
        "status": "available",
108
        "name": "Gardenia",
109
        "checksum": "06d3099815d1f6fada91e80107638b882",
110
        "created_at": "2013-02-13 12:35:21",
111
        "disk_format": "diskdump",
112
        "updated_at": "2013-02-13 12:35:23",
113
        "properties": {
114
            "partition_table": "msdos",
115
            "osfamily": "linux",
116
            "description": "Ubuntu 12.04.2 LTS",
117
            "os": "ubuntu",
118
            "root_partition": "1",
119
            "users": "user"},
120
        "location": "pithos://us3r-E-1d/images/Gardenia-201302131431.diskdump",
121
        "container_format": "bare",
122
        "owner": "user3@mail.example.com",
123
        "is_public": True,
124
        "deleted_at": "",
125
        "id": "5963020b-ab74-4e11-bc59-90c494bbdedb",
126
        "size": 2589802496}]
127

    
128

    
129
class Image(TestCase):
130

    
131
    def assert_dicts_are_deeply_equal(self, d1, d2):
132
        for k, v in d1.items():
133
            self.assertTrue(k in d2)
134
            if isinstance(v, dict):
135
                self.assert_dicts_are_deeply_equal(v, d2[k])
136
            else:
137
                self.assertEqual(unicode(v), unicode(d2[k]))
138

    
139
    class FR(object):
140
        json = example_images
141
        headers = {}
142
        content = json
143
        status = None
144
        status_code = 200
145

    
146
        def release(self):
147
            pass
148

    
149
    def setUp(self):
150
        self.url = 'http://image.example.com'
151
        self.token = 'an1m@g370k3n=='
152
        from kamaki.clients.image import ImageClient
153
        self.client = ImageClient(self.url, self.token)
154
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
155
        self.C = KamakiHTTPConnection
156

    
157
    def tearDown(self):
158
        self.FR.json = example_images
159
        self.FR.status_code = 200
160

    
161
    def test_list_public(self):
162
        with patch.object(
163
            self.C,
164
            'perform_request',
165
            return_value=self.FR()) as perform_req:
166
            r = self.client.list_public()
167
            self.assertEqual(self.client.http_client.url, self.url)
168
            self.assertEqual(self.client.http_client.path, '/images/')
169
            params = perform_req.call_args[0][3]
170
            self.assertEqual(params['sort_dir'], 'asc')
171
            for i in range(len(r)):
172
                self.assert_dicts_are_deeply_equal(r[i], example_images[i])
173

    
174
            r = self.client.list_public(order='-')
175
            params = perform_req.call_args[0][3]
176
            self.assertEqual(params['sort_dir'], 'desc')
177
            self.assertEqual(self.client.http_client.url, self.url)
178
            self.assertEqual(self.client.http_client.path, '/images/')
179

    
180
            self.FR.json = example_images_detailed
181
            r = self.client.list_public(detail=True)
182
            self.assertEqual(self.client.http_client.url, self.url)
183
            self.assertEqual(self.client.http_client.path, '/images/detail')
184
            for i in range(len(r)):
185
                self.assert_dicts_are_deeply_equal(
186
                    r[i],
187
                    example_images_detailed[i])
188

    
189
            size_max = 1000000000
190
            r = self.client.list_public(filters=dict(size_max=size_max))
191
            params = perform_req.call_args[0][3]
192
            self.assertEqual(params['size_max'], size_max)
193
            self.assertEqual(self.client.http_client.url, self.url)
194
            self.assertEqual(self.client.http_client.path, '/images/')
195

    
196
    def test_get_meta(self):
197
        img0 = example_images[0]
198
        self.FR.json = img0
199
        img0_headers = {}
200
        for k, v in example_images_detailed[0].items():
201
            img0_headers['x-image-meta-%s' % k] = v
202
        self.FR.headers = img0_headers
203
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
204
            r = self.client.get_meta(img0['id'])
205
            self.assertEqual(self.client.http_client.url, self.url)
206
            expected_path = '/images/%s' % img0['id']
207
            self.assertEqual(self.client.http_client.path, expected_path)
208

    
209
            self.assertEqual(r['id'], img0['id'])
210
            self.assert_dicts_are_deeply_equal(r, example_images_detailed[0])
211

    
212
    def test_register(self):
213
        img0 = example_images_detailed[0]
214
        img0_location = img0['location']
215
        img0_name = 'A new img0 name'
216
        with patch.object(
217
                self.C,
218
                'perform_request',
219
                return_value=self.FR()) as perform_req:
220
            self.client.register(img0_name, img0_location)
221
            self.assertEqual(self.client.http_client.url, self.url)
222
            self.assertEqual(self.client.http_client.path, '/images/')
223
            (method, data, headers, params) = perform_req.call_args[0]
224
            self.assertEqual(method, 'post')
225
            self.assertTrue(0 == len(params))
226

    
227
            val = 'Some random value'
228
            param_dict = dict(
229
                id=val,
230
                store=val,
231
                disk_format=val,
232
                container_format=val,
233
                size=val,
234
                checksum=val,
235
                is_public=val,
236
                owner=val)
237
            for key in param_dict.keys():
238
                param = {key: val}
239
                self.client.register(img0_name, img0_location, params=param)
240
                (method, data, a_headers, a_params) = perform_req.call_args[0]
241
                key = 'x-image-meta-%s' % key.replace('_', '-')
242
                self.assertEqual(a_headers[key], val)
243
            self.client.register(img0_name, img0_location, params=param_dict)
244
            (method, data, a_headers, a_params) = perform_req.call_args[0]
245
            self.assertEqual(len(param_dict), len(a_headers))
246
            for key, val in param_dict.items():
247
                key = 'x-image-meta-%s' % key.replace('_', '-')
248
                self.assertEqual(a_headers[key], val)
249

    
250
            props = dict(key0='val0', key2='val2', key3='val3')
251
            self.client.register(img0_name, img0_location, properties=props)
252
            (method, data, a_headers, a_params) = perform_req.call_args[0]
253
            for k, v in props.items():
254
                self.assertEquals(a_headers['X-Image-Meta-Property-%s' % k], v)
255

    
256
    def test_set_members(self):
257
        img0 = example_images_detailed[0]
258
        members = ['use3r-1d-0', 'us2r-1d-1', 'us3r-1d-2']
259
        with patch.object(
260
                self.C,
261
                'perform_request',
262
                return_value=self.FR()) as perform_req:
263
            self.assertRaises(
264
                ClientError,
265
                self.client.set_members,
266
                img0['id'], members)
267
            self.FR.status_code = 204
268
            self.client.set_members(img0['id'], members)
269
            self.assertEqual(self.client.http_client.url, self.url)
270
            self.assertEqual(
271
                    self.client.http_client.path,
272
                '/images/%s/members' % img0['id'])
273
            (method, data, a_headers, a_params) = perform_req.call_args[0]
274
            from json import loads
275
            memberships = loads(data)['memberships']
276
            for membership in memberships:
277
                self.assertTrue(membership['member_id'] in members)
278

    
279
    def test_list_members(self):
280
        img0 = example_images_detailed[0]
281
        members = ['use3r-1d-0', 'us2r-1d-1', 'us3r-1d-2']
282
        self.FR.json = dict(members=members)
283
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
284
            r = self.client.list_members(img0['id'])
285
            self.assertEqual(self.client.http_client.url, self.url)
286
            self.assertEqual(
287
                self.client.http_client.path,
288
                '/images/%s/members' % img0['id'])
289
            self.assertEqual(r, members)
290

    
291
    def test_add_member(self):
292
        img0 = example_images_detailed[0]
293
        new_member = 'us3r-15-n3w'
294
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
295
            self.assertRaises(
296
                ClientError,
297
                self.client.add_member,
298
                img0['id'], new_member)
299
            self.FR.status_code = 204
300
            self.client.add_member(img0['id'], new_member)
301
            self.assertEqual(self.client.http_client.url, self.url)
302
            self.assertEqual(
303
                self.client.http_client.path,
304
                '/images/%s/members/%s' % (img0['id'], new_member))
305

    
306
    def test_remove_member(self):
307
        img0 = example_images_detailed[0]
308
        old_member = 'us3r-15-0ld'
309
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
310
            self.assertRaises(
311
                ClientError,
312
                self.client.remove_member,
313
                img0['id'], old_member)
314
            self.FR.status_code = 204
315
            self.client.remove_member(img0['id'], old_member)
316
            self.assertEqual(self.client.http_client.url, self.url)
317
            self.assertEqual(
318
                self.client.http_client.path,
319
                '/images/%s/members/%s' % (img0['id'], old_member))
320

    
321
    def test_list_shared(self):
322
        img0 = example_images_detailed[0]
323
        self.FR.json = dict(shared_images=example_images)
324
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
325
            r = self.client.list_shared(img0['id'])
326
            self.assertEqual(self.client.http_client.url, self.url)
327
            self.assertEqual(
328
                self.client.http_client.path,
329
                '/shared-images/%s' % img0['id'])
330
            for i in range(len(r)):
331
                self.assert_dicts_are_deeply_equal(r[i], example_images[i])