Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.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
import time
36

    
37
from unittest import TestCase
38
from kamaki.clients import ClientError
39

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

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

    
129

    
130
class Image(TestCase):
131

    
132
    class FR(object):
133
        json = example_images
134
        headers = {}
135
        content = json
136
        status = None
137
        status_code = 200
138

    
139
        def release(self):
140
            pass
141

    
142
    def setUp(self):
143
        self.now = time.mktime(time.gmtime())
144
        self.imgname = 'img_%s' % self.now
145
        self.url = 'http://image.example.com'
146
        self.token = 'an1m@g370k3n=='
147
        from kamaki.clients.image import ImageClient
148
        self.client = ImageClient(self.url, self.token)
149
        self.cyclades_url = 'http://cyclades.example.com'
150
        from kamaki.clients.cyclades import CycladesClient
151
        self.cyclades = CycladesClient(self.cyclades_url, self.token)
152
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
153
        self.C = KamakiHTTPConnection
154

    
155
    def tearDown(self):
156
        self.FR.json = example_images
157
        self.FR.status_code = 200
158

    
159
    def assert_dicts_are_deeply_equal(self, d1, d2):
160
        for k, v in d1.items():
161
            self.assertTrue(k in d2)
162
            if isinstance(v, dict):
163
                self.assert_dicts_are_deeply_equal(v, d2[k])
164
            else:
165
                self.assertEqual(unicode(v), unicode(d2[k]))
166

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

    
180
            r = self.client.list_public(order='-')
181
            params = perform_req.call_args[0][3]
182
            self.assertEqual(params['sort_dir'], 'desc')
183
            self.assertEqual(self.client.http_client.url, self.url)
184
            self.assertEqual(self.client.http_client.path, '/images/')
185

    
186
            self.FR.json = example_images_detailed
187
            r = self.client.list_public(detail=True)
188
            self.assertEqual(self.client.http_client.url, self.url)
189
            self.assertEqual(self.client.http_client.path, '/images/detail')
190
            for i in range(len(r)):
191
                self.assert_dicts_are_deeply_equal(
192
                    r[i],
193
                    example_images_detailed[i])
194

    
195
            size_max = 1000000000
196
            r = self.client.list_public(filters=dict(size_max=size_max))
197
            params = perform_req.call_args[0][3]
198
            self.assertEqual(params['size_max'], size_max)
199
            self.assertEqual(self.client.http_client.url, self.url)
200
            self.assertEqual(self.client.http_client.path, '/images/')
201

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

    
215
            self.assertEqual(r['id'], img0['id'])
216
            self.assert_dicts_are_deeply_equal(r, example_images_detailed[0])
217

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

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

    
256
            props = dict(key0='val0', key2='val2', key3='val3')
257
            self.client.register(img0_name, img0_location, properties=props)
258
            (method, data, a_headers, a_params) = perform_req.call_args[0]
259
            for k, v in props.items():
260
                self.assertEquals(a_headers['X-Image-Meta-Property-%s' % k], v)
261

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

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

    
289
    """
290
    def test_remove_members(self):
291
        ""Test remove_members - NO CHECK""
292
        self._prepare_img()
293
        self._test_remove_members()
294

295
    def _test_remove_members(self):
296
        return
297
        members = ['%s@fake.net' % self.now, '%s_v2@fake.net' % self.now]
298
        for img in self._imglist.values():
299
            self.client.set_members(img['id'], members)
300
            r = self.client.list_members(img['id'])
301
            self.assertTrue(len(r) > 1)
302
            self.client.remove_member(img['id'], members[0])
303
            r0 = self.client.list_members(img['id'])
304
            self.assertEqual(len(r), 1 + len(r0))
305
            self.assertEqual(r0[0]['member_id'], members[1])
306

307
    def test_list_shared(self):
308
        ""Test list_shared - NOT CHECKED""
309
        self._test_list_shared()
310

311
    def _test_list_shared(self):
312
        #No way to test this, if I dont have member images
313
        pass
314
    """