Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / test.py @ 1df5305d

History | View | Annotate | Download (12.6 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 mock import patch, call
35
from unittest import TestCase
36

    
37
from kamaki.clients import ClientError
38
from kamaki.clients.cyclades import CycladesClient
39

    
40

    
41
compute_pkg = 'kamaki.clients.cyclades.CycladesClient'
42

    
43
img_ref = "1m4g3-r3f3r3nc3"
44
vm_name = "my new VM"
45
fid = 42
46
vm_send = dict(server=dict(
47
    flavorRef=fid,
48
    name=vm_name,
49
    imageRef=img_ref,
50
    metadata=dict(os="debian", users="root")))
51
vm_recv = dict(server=dict(
52
    status="BUILD",
53
    updated="2013-03-01T10:04:00.637152+00:00",
54
    hostId="",
55
    name=vm_name,
56
    imageRef=img_ref,
57
    created="2013-03-01T10:04:00.087324+00:00",
58
    flavorRef=fid,
59
    adminPass="n0n3sh@11p@55",
60
    suspended=False,
61
    progress=0,
62
    id=31173,
63
    metadata=dict(values=dict(os="debian", users="root"))))
64
img_recv = dict(image=dict(
65
    status="ACTIVE",
66
    updated="2013-02-26T11:10:14+00:00",
67
    name="Debian Base",
68
    created="2013-02-26T11:03:29+00:00",
69
    progress=100,
70
    id=img_ref,
71
    metadata=dict(values=dict(
72
        partition_table="msdos",
73
        kernel="2.6.32",
74
        osfamily="linux",
75
        users="root",
76
        gui="No GUI",
77
        sortorder="1",
78
        os="debian",
79
        root_partition="1",
80
        description="Debian 6.0.7 (Squeeze) Base System"))))
81
vm_list = dict(servers=dict(values=[
82
    dict(name='n1', id=1),
83
    dict(name='n2', id=2)]))
84
flavor_list = dict(flavors=dict(values=[
85
    dict(id=41, name="C1R1024D20"),
86
    dict(id=42, name="C1R1024D40"),
87
    dict(id=43, name="C1R1028D20")]))
88
img_list = dict(images=dict(values=[
89
    dict(name="maelstrom", id="0fb03e45-7d5a-4515-bd4e-e6bbf6457f06"),
90
    dict(name="edx_saas", id="1357163d-5fd8-488e-a117-48734c526206"),
91
    dict(name="Debian_Wheezy_Base", id="1f8454f0-8e3e-4b6c-ab8e-5236b728dffe"),
92
    dict(name="CentOS", id="21894b48-c805-4568-ac8b-7d4bb8eb533d"),
93
    dict(name="Ubuntu Desktop", id="37bc522c-c479-4085-bfb9-464f9b9e2e31"),
94
    dict(name="Ubuntu 12.10", id="3a24fef9-1a8c-47d1-8f11-e07bd5e544fd"),
95
    dict(name="Debian Base", id="40ace203-6254-4e17-a5cb-518d55418a7d"),
96
    dict(name="ubuntu_bundled", id="5336e265-5c7c-4127-95cb-2bf832a79903")]))
97

    
98

    
99
class FR(object):
100
    """FR stands for Fake Response"""
101
    json = vm_recv
102
    headers = {}
103
    content = json
104
    status = None
105
    status_code = 200
106

    
107
    def release(self):
108
        pass
109

    
110

    
111
class Cyclades(TestCase):
112

    
113
    def assert_dicts_are_equal(self, d1, d2):
114
        for k, v in d1.items():
115
            self.assertTrue(k in d2)
116
            if isinstance(v, dict):
117
                self.assert_dicts_are_equal(v, d2[k])
118
            else:
119
                self.assertEqual(unicode(v), unicode(d2[k]))
120

    
121
    """Set up a Cyclades thorough test"""
122
    def setUp(self):
123
        self.url = 'http://cyclades.example.com'
124
        self.token = 'cyc14d3s70k3n'
125
        self.client = CycladesClient(self.url, self.token)
126
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
127
        self.C = KamakiHTTPConnection
128

    
129
    def tearDown(self):
130
        FR.status_code = 200
131
        FR.json = vm_recv
132

    
133
    @patch(
134
        '%s.get_image_details' % compute_pkg,
135
        return_value=img_recv['image'])
136
    def test_create_server(self, GID):
137
        with patch.object(
138
                CycladesClient, 'servers_post',
139
                side_effect=ClientError(
140
                    'REQUEST ENTITY TOO LARGE',
141
                    status=403)):
142
            self.assertRaises(
143
                ClientError,
144
                self.client.create_server,
145
                vm_name, fid, img_ref)
146

    
147
        with patch.object(
148
                CycladesClient, 'servers_post',
149
                return_value=FR()) as post:
150
            r = self.client.create_server(vm_name, fid, img_ref)
151
            self.assertEqual(r, FR.json['server'])
152
            self.assertEqual(GID.mock_calls[-1], call(img_ref))
153
            self.assertEqual(post.mock_calls[-1], call(json_data=vm_send))
154
            prsn = 'Personality string (does not work with real servers)'
155
            self.client.create_server(vm_name, fid, img_ref, prsn)
156
            expected = dict(server=dict(vm_send['server']))
157
            expected['server']['personality'] = prsn
158
            self.assertEqual(post.mock_calls[-1], call(json_data=expected))
159

    
160
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
161
    def test_list_servers(self, SG):
162
        FR.json = vm_list
163
        for detail in (False, True):
164
            r = self.client.list_servers(detail)
165
            self.assertEqual(SG.mock_calls[-1], call(
166
                changes_since=None,
167
                command='detail' if detail else ''))
168
            for i, vm in enumerate(vm_list['servers']['values']):
169
                self.assert_dicts_are_equal(r[i], vm)
170
            self.assertEqual(i + 1, len(r))
171

    
172
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
173
    def test_get_server_details(self, SG):
174
        vm_id = vm_recv['server']['id']
175
        r = self.client.get_server_details(vm_id)
176
        SG.assert_called_once_with(vm_id)
177
        self.assert_dicts_are_equal(r, vm_recv['server'])
178

    
179
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
180
    def test_update_server_name(self, SP):
181
        vm_id = vm_recv['server']['id']
182
        new_name = vm_name + '_new'
183
        self.client.update_server_name(vm_id, new_name)
184
        SP.assert_called_once_with(vm_id, json_data=dict(
185
            server=dict(name=new_name)))
186

    
187
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
188
    def test_reboot_server(self, SP):
189
        vm_id = vm_recv['server']['id']
190
        for hard in (None, True):
191
            self.client.reboot_server(vm_id, hard=hard)
192
            self.assertEqual(SP.mock_calls[-1], call(
193
                vm_id, 'action',
194
                json_data=dict(reboot=dict(type='HARD' if hard else 'SOFT'))))
195

    
196
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
197
    def test_create_server_metadata(self, SP):
198
        vm_id = vm_recv['server']['id']
199
        metadata = dict(m1='v1', m2='v2', m3='v3')
200
        FR.json = dict(meta=vm_recv['server'])
201
        for k, v in metadata.items():
202
            r = self.client.create_server_metadata(vm_id, k, v)
203
            self.assert_dicts_are_equal(r, vm_recv['server'])
204
            self.assertEqual(SP.mock_calls[-1], call(
205
                vm_id, 'meta/%s' % k,
206
                json_data=dict(meta={k: v}), success=201))
207

    
208
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
209
    def test_get_server_metadata(self, SG):
210
        vm_id = vm_recv['server']['id']
211
        metadata = dict(m1='v1', m2='v2', m3='v3')
212
        FR.json = dict(metadata=dict(values=metadata))
213
        r = self.client.get_server_metadata(vm_id)
214
        SG.assert_called_once_with(vm_id, '/meta')
215
        self.assert_dicts_are_equal(r, metadata)
216

    
217
        for k, v in metadata.items():
218
            FR.json = dict(meta={k: v})
219
            r = self.client.get_server_metadata(vm_id, k)
220
            self.assert_dicts_are_equal(r, {k: v})
221
            self.assertEqual(SG.mock_calls[-1], call(vm_id, '/meta/%s' % k))
222

    
223
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
224
    def test_update_server_metadata(self, SP):
225
        vm_id = vm_recv['server']['id']
226
        metadata = dict(m1='v1', m2='v2', m3='v3')
227
        FR.json = dict(metadata=metadata)
228
        r = self.client.update_server_metadata(vm_id, **metadata)
229
        self.assert_dicts_are_equal(r, metadata)
230
        SP.assert_called_once_with(
231
            vm_id, 'meta',
232
            json_data=dict(metadata=metadata), success=201)
233

    
234
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
235
    def test_delete_server_metadata(self, SD):
236
        vm_id = vm_recv['server']['id']
237
        key = 'metakey'
238
        self.client.delete_server_metadata(vm_id, key)
239
        SD.assert_called_once_with(vm_id, 'meta/' + key)
240

    
241
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
242
    def test_list_flavors(self, FG):
243
        FR.json = flavor_list
244
        for cmd in ('', 'detail'):
245
            r = self.client.list_flavors(detail=(cmd == 'detail'))
246
            self.assertEqual(FG.mock_calls[-1], call(command=cmd))
247
            self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
248

    
249
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
250
    def test_get_flavor_details(self, FG):
251
        FR.json = dict(flavor=flavor_list['flavors'])
252
        r = self.client.get_flavor_details(fid)
253
        FG.assert_called_once_with(fid)
254
        self.assert_dicts_are_equal(r, flavor_list['flavors'])
255

    
256
    @patch('%s.images_get' % compute_pkg, return_value=FR())
257
    def test_list_images(self, IG):
258
        FR.json = img_list
259
        for cmd in ('', 'detail'):
260
            r = self.client.list_images(detail=(cmd == 'detail'))
261
            self.assertEqual(IG.mock_calls[-1], call(command=cmd))
262
            expected = img_list['images']['values']
263
            for i in range(len(r)):
264
                self.assert_dicts_are_equal(expected[i], r[i])
265

    
266
    @patch('%s.images_get' % compute_pkg, return_value=FR())
267
    def test_get_image_details(self, IG):
268
        FR.json = img_recv
269
        r = self.client.get_image_details(img_ref)
270
        IG.assert_called_once_with(img_ref)
271
        self.assert_dicts_are_equal(r, img_recv['image'])
272

    
273
    @patch('%s.images_get' % compute_pkg, return_value=FR())
274
    def test_get_image_metadata(self, IG):
275
        for key in ('', '50m3k3y'):
276
            FR.json = dict(meta=img_recv['image']) if (
277
                key) else dict(metadata=dict(values=img_recv['image']))
278
            r = self.client.get_image_metadata(img_ref, key)
279
            self.assertEqual(IG.mock_calls[-1], call(
280
                '%s' % img_ref,
281
                '/meta%s' % (('/%s' % key) if key else '')))
282
            self.assert_dicts_are_equal(img_recv['image'], r)
283

    
284
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
285
    def test_delete_server(self, SD):
286
        vm_id = vm_recv['server']['id']
287
        self.client.delete_server(vm_id)
288
        SD.assert_called_once_with(vm_id)
289

    
290
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
291
    def test_delete_image(self, ID):
292
        self.client.delete_image(img_ref)
293
        ID.assert_called_once_with(img_ref)
294

    
295
    @patch('%s.images_put' % compute_pkg, return_value=FR())
296
    def test_create_image_metadata(self, IP):
297
        (key, val) = ('k1', 'v1')
298
        FR.json = dict(meta=img_recv['image'])
299
        r = self.client.create_image_metadata(img_ref, key, val)
300
        IP.assert_called_once_with(
301
            img_ref, 'meta/%s' % key,
302
            json_data=dict(meta={key: val}))
303
        self.assert_dicts_are_equal(r, img_recv['image'])
304

    
305
    @patch('%s.images_post' % compute_pkg, return_value=FR())
306
    def test_update_image_metadata(self, IP):
307
        metadata = dict(m1='v1', m2='v2', m3='v3')
308
        FR.json = dict(metadata=metadata)
309
        r = self.client.update_image_metadata(img_ref, **metadata)
310
        IP.assert_called_once_with(
311
            img_ref, 'meta',
312
            json_data=dict(metadata=metadata))
313
        self.assert_dicts_are_equal(r, metadata)
314

    
315
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
316
    def test_delete_image_metadata(self, ID):
317
        key = 'metakey'
318
        self.client.delete_image_metadata(img_ref, key)
319
        ID.assert_called_once_with(img_ref, '/meta/%s' % key)
320

    
321
if __name__ == '__main__':
322
    from sys import argv
323
    from kamaki.clients.test import runTestCase
324
    runTestCase(Cyclades, 'Cyclades (multi) Client', argv[1:])