Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / test.py @ 4a88f05b

History | View | Annotate | Download (29 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
from itertools import product
37
from json import dumps
38
from sys import stdout
39
import json
40

    
41
from kamaki.clients import ClientError, compute
42

    
43

    
44
rest_pkg = 'kamaki.clients.compute.rest_api.ComputeRestClient'
45
compute_pkg = 'kamaki.clients.compute.ComputeClient'
46

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

    
102

    
103
class FR(object):
104
    """FR stands for Fake Response"""
105
    json = vm_recv
106
    headers = {}
107
    content = json
108
    status = None
109
    status_code = 200
110

    
111

    
112
def print_iterations(old, new):
113
    if new:
114
        if new % 1000:
115
            return old
116
        stdout.write('\b' * len('%s' % old))
117
        stdout.write('%s' % new)
118
    else:
119
        stdout.write('# of loops:  ')
120
    stdout.flush()
121
    return new
122

    
123

    
124
class ComputeRestClient(TestCase):
125

    
126
    """Set up a ComputesRest thorough test"""
127
    def setUp(self):
128
        self.url = 'http://cyclades.example.com'
129
        self.token = 'cyc14d3s70k3n'
130
        self.client = compute.ComputeRestClient(self.url, self.token)
131

    
132
    def tearDown(self):
133
        FR.json = vm_recv
134

    
135
    @patch('%s.set_param' % rest_pkg)
136
    @patch('%s.get' % rest_pkg, return_value=FR())
137
    def _test_get(self, service, params, get, set_param):
138
        method = getattr(self.client, '%s_get' % service)
139
        param_args = [({}, {k: k}, {k: v[1]}) for k, v in params.items()]
140
        num_of_its = 0
141
        for i, args in enumerate(product(
142
                ('', '%s_id' % service),
143
                (None, False, True),
144
                (200, 204),
145
                ({}, {'k': 'v'}),
146
                *param_args)):
147
            (srv_id, detail, success, kwargs) = args[:4]
148
            kwargs['success'] = success
149
            srv_kwargs = dict()
150
            for param in args[4:]:
151
                srv_kwargs.update(param)
152
            srv_kwargs.update(kwargs)
153
            method(*args[:2], **srv_kwargs)
154
            srv_str = '/detail' if detail else (
155
                '/%s' % srv_id) if srv_id else ''
156
            self.assertEqual(
157
                get.mock_calls[-1],
158
                call('/%s%s' % (service, srv_str), **kwargs))
159
            param_calls = []
160
            for k, v in params.items():
161
                real_v = srv_kwargs.get(k, v[1]) if not srv_id else v[1]
162
                param_calls.append(call(v[0], real_v, iff=real_v))
163
            actual = set_param.mock_calls[- len(param_calls):]
164
            self.assertEqual(sorted(actual), sorted(param_calls))
165

    
166
            num_of_its = print_iterations(num_of_its, i)
167
        print ('\b' * len('%s' % num_of_its)) + ('%s' % i)
168

    
169
    @patch('%s.set_param' % rest_pkg)
170
    @patch('%s.get' % rest_pkg, return_value=FR())
171
    def _test_srv_cmd_get(self, srv, cmd, params, get, set_param):
172
        method = getattr(self.client, '%s_%s_get' % (srv, cmd))
173
        param_args = [({}, {k: k}, {k: v[1]}) for k, v in params.items()]
174
        num_of_its = 0
175
        for i, args in enumerate(product(
176
                ('some_server_id', 'other_server_id'),
177
                (None, 'xtra_id'),
178
                ((304, 200), (1000)),
179
                ({}, {'k': 'v'}),
180
                *param_args)):
181
            srv_id, xtra_id, success, kwargs = args[:4]
182
            kwargs = dict(kwargs)
183
            kwargs['success'] = success
184
            srv_kwargs = dict()
185
            for param in args[4:]:
186
                srv_kwargs.update(param)
187
            srv_kwargs.update(kwargs)
188
            method(*args[:2], **srv_kwargs)
189
            srv_str = '/%s/%s/%s' % (srv, srv_id, cmd)
190
            srv_str += ('/%s' % xtra_id) if xtra_id else ''
191
            self.assertEqual(get.mock_calls[-1], call(srv_str, **kwargs))
192
            param_calls = []
193
            for k, v in params.items():
194
                real_v = srv_kwargs.get(k, v[1])
195
                param_calls.append(call(v[0], real_v, iff=real_v))
196
            actual = set_param.mock_calls[- len(param_calls):]
197
            self.assertEqual(sorted(actual), sorted(param_calls))
198

    
199
            num_of_its = print_iterations(num_of_its, i)
200
        print ('\b' * len('%s' % num_of_its)) + ('%s' % i)
201

    
202
    @patch('%s.set_header' % rest_pkg)
203
    @patch('%s.set_param' % rest_pkg)
204
    @patch('%s.post' % rest_pkg, return_value=FR())
205
    def _test_post(self, srv, cmd, params, post, set_param, set_header):
206
        method = getattr(
207
            self.client, '%s_%spost' % (srv, ('%s_' % cmd) if cmd else ''))
208
        param_args = [({}, {k: k}, {k: v[1]}) for k, v in params.items()]
209
        num_of_its = 0
210
        for i, args in enumerate(product(
211
                ('%s_id' % srv, 'some_value'),
212
                (
213
                    None,
214
                    {'some': {'data': 'in json'}},
215
                    ['k1', {'k2': 'v2', 'k3': 'v3'}, 'k4']),
216
                (202, 1453),
217
                ({}, {'k': 'v'}),
218
                *param_args)):
219
            srv_id, json_data, success, kwargs = args[:4]
220
            kwargs = dict(kwargs)
221
            cmd_args = (srv_id, ) if cmd else ()
222
            kwargs['success'] = success
223
            srv_kwargs = dict()
224
            for param in args[4:]:
225
                srv_kwargs.update(param)
226
            srv_kwargs.update(kwargs)
227
            srv_kwargs['json_data'] = json_data
228
            method(*cmd_args, **srv_kwargs)
229
            srv_str = '/%s%s' % (
230
                srv, (('/%s/%s' % (srv_id, cmd)) if cmd else ''))
231
            kwargs['data'] = json.dumps(json_data) if json_data else None
232
            self.assertEqual(post.mock_calls[-1], call(srv_str, **kwargs))
233

    
234
            param_calls = []
235
            for k, v in params.items():
236
                real_v = srv_kwargs.get(k, v[1])
237
                param_calls.append(call(v[0], real_v, iff=real_v))
238
            actual = set_param.mock_calls[- len(param_calls):]
239
            self.assertEqual(sorted(actual), sorted(param_calls))
240

    
241
            if json_data:
242
                self.assertEqual(set_header.mock_calls[-2:], [
243
                    call('Content-Type', 'application/json'),
244
                    call('Content-Length', len(kwargs['data']))])
245

    
246
            num_of_its = print_iterations(num_of_its, i)
247
        print ('\b' * len('%s' % num_of_its)) + ('%s' % i)
248

    
249
    @patch('%s.set_header' % rest_pkg)
250
    @patch('%s.set_param' % rest_pkg)
251
    @patch('%s.put' % rest_pkg, return_value=FR())
252
    def _test_put(self, srv, cmd, params, put, set_param, set_headers):
253
        method = getattr(self.client, '%s_%sput' % (
254
            srv, ('%s_' % cmd) if cmd else ''))
255
        param_args = [({}, {k: k}, {k: v[1]}) for k, v in params.items()]
256
        num_of_its = 0
257
        for i, args in enumerate(product(
258
                ('some_value', '%s_id' % srv),
259
                (None, [dict(json="data"), dict(data="json")]),
260
                (204, 504),
261
                ({}, {'k': 'v'}),
262
                *param_args)):
263
            srv_id, json_data, success, kwargs = args[:4]
264
            kwargs = dict(kwargs)
265
            kwargs['success'] = success
266
            srv_kwargs = dict()
267
            for param in args[4:]:
268
                srv_kwargs.update(param)
269
            srv_kwargs.update(kwargs)
270
            srv_kwargs['json_data'] = json_data
271
            method(srv_id, **srv_kwargs)
272
            srv_str = '/%s/%s%s' % (srv, srv_id, ('/%s' % cmd if cmd else ''))
273

    
274
            if json_data:
275
                json_data = dumps(json_data)
276
                self.assertEqual(set_headers.mock_calls[-2:], [
277
                    call('Content-Type', 'application/json'),
278
                    call('Content-Length', len(json_data))])
279
            self.assertEqual(
280
                put.mock_calls[-1],
281
                call(srv_str, data=json_data, **kwargs))
282

    
283
            param_calls = []
284
            for k, v in params.items():
285
                real_v = srv_kwargs.get(k, v[1])
286
                param_calls.append(call(v[0], real_v, iff=real_v))
287
            actual = set_param.mock_calls[- len(param_calls):]
288
            self.assertEqual(sorted(actual), sorted(param_calls))
289

    
290
            num_of_its = print_iterations(num_of_its, i)
291
        print ('\b' * len('%s' % num_of_its)) + ('%s' % i)
292

    
293
    @patch('%s.delete' % rest_pkg, return_value=FR())
294
    def _test_delete(self, srv, cmd, delete):
295
        method = getattr(
296
            self.client, '%s_%sdelete' % (srv, ('%s_' % cmd) if cmd else ''))
297
        cmd_params = ('some_cmd_value', 'some_other_value') if cmd else ()
298
        num_of_its = 0
299
        for i, args in enumerate(product(
300
                ('%s_id' % srv, 'some_value'),
301
                (204, 208),
302
                ({}, {'k': 'v'}),
303
                *cmd_params)):
304
            (srv_id, success, kwargs) = args[:3]
305
            kwargs = dict(kwargs)
306
            kwargs['success'] = success
307
            cmd_value = args[-1] if cmd else ''
308
            method_args = (srv_id, cmd_value) if cmd else (srv_id, )
309
            method(*method_args, **kwargs)
310
            srv_str = '/%s/%s' % (srv, srv_id)
311
            cmd_str = ('/%s/%s' % (cmd, cmd_value)) if cmd else ''
312
            self.assertEqual(
313
                delete.mock_calls[-1],
314
                call('%s%s' % (srv_str, cmd_str), **kwargs))
315
            num_of_its = print_iterations(num_of_its, i)
316
        print ('\b' * len('%s' % num_of_its)) + ('%s' % i)
317

    
318
    @patch('%s.get' % rest_pkg, return_value=FR())
319
    def test_limits_get(self, get):
320
        self.client.limits_get(success='some_val')
321
        get.assert_called_once_with('/limits', success='some_val')
322

    
323
    def test_servers_get(self):
324
        params = dict(
325
            changes_since=('changes-since', None),
326
            image=('image', None),
327
            flavor=('flavor', None),
328
            name=('name', None),
329
            marker=('marker', None),
330
            limit=('limit', None),
331
            status=('status', None),
332
            host=('host', None))
333
        self._test_get('servers', params)
334

    
335
    def test_servers_post(self):
336
        params = dict(
337
            security_group=('security_group', None),
338
            user_data=('user_data', None),
339
            availability_zone=('availability_zone', None))
340
        self._test_post('servers', None, params)
341

    
342
    def test_servers_put(self):
343
        self._test_put('servers', None, dict(server_name=('server', None)))
344

    
345
    def test_servers_delete(self):
346
        self._test_delete('servers', None)
347

    
348
    def test_servers_metadata_get(self):
349
        self._test_srv_cmd_get('servers', 'metadata', {})
350

    
351
    def test_servers_metadata_post(self):
352
        self._test_post('servers', 'metadata', {})
353

    
354
    def test_servers_metadata_put(self):
355
        self._test_put('servers', 'metadata', {})
356

    
357
    def test_images_metadata_delete(self):
358
        self._test_delete('images', 'metadata')
359

    
360
    def test_servers_action_post(self):
361
        self._test_post('servers', 'action', {})
362

    
363
    def test_servers_ips_get(self):
364
        params = dict(changes_since=('changes-since', None))
365
        self._test_srv_cmd_get('servers', 'ips', params)
366

    
367
    def test_images_get(self):
368
        param = dict(
369
            changes_since=('changes-since', None),
370
            server_name=('server', None),
371
            name=('name', None),
372
            status=('status', None),
373
            marker=('marker', None),
374
            limit=('limit', None),
375
            type=('type', None))
376
        self._test_get('images', param)
377

    
378
    def test_images_delete(self):
379
        self._test_delete('images', None)
380

    
381
    def test_images_metadata_get(self):
382
        self._test_srv_cmd_get('images', 'metadata', {})
383

    
384
    def test_images_metadata_post(self):
385
        self._test_post('images', 'metadata', {})
386

    
387
    def test_images_metadata_put(self):
388
        self._test_put('images', 'metadata', {})
389

    
390
    def test_servers_metadata_delete(self):
391
        self._test_delete('servers', 'metadata')
392

    
393
    def test_flavors_get(self):
394
        params = dict(
395
            changes_since=('changes-since', None),
396
            minDisk=('minDisk', None),
397
            minRam=('minRam', None),
398
            marker=('marker', None),
399
            limit=('limit', None))
400
        self._test_get('flavors', params)
401

    
402
    @patch('%s.get' % rest_pkg, return_value=FR())
403
    def test_floating_ip_pools_get(self, get):
404
        for args in product(
405
                (200, 204),
406
                ({}, {'k': 'v'})):
407
            success, kwargs = args
408
            r = self.client.floating_ip_pools_get(success, **kwargs)
409
            self.assertTrue(isinstance(r, FR))
410
            self.assertEqual(get.mock_calls[-1], call(
411
                '/os-floating-ip-pools', success=success, **kwargs))
412

    
413
    @patch('%s.get' % rest_pkg, return_value=FR())
414
    def test_floating_ips_get(self, get):
415
        for args in product(
416
                ('', '192.193.194.195'),
417
                (200, 204),
418
                ({}, {'k': 'v'})):
419
            ip, success, kwargs = args
420
            r = self.client.floating_ips_get(*args[:2], **kwargs)
421
            self.assertTrue(isinstance(r, FR))
422
            expected = '' if not ip else '/%s' % ip
423
            self.assertEqual(get.mock_calls[-1], call(
424
                '/os-floating-ips%s' % expected, success=success, **kwargs))
425

    
426
    @patch('%s.set_header' % rest_pkg)
427
    @patch('%s.post' % rest_pkg, return_value=FR())
428
    def test_floating_ips_post(self, post, SH):
429
        for args in product(
430
                (None, [dict(json="data"), dict(data="json")]),
431
                ('', '192.193.194.195'),
432
                (202, 204),
433
                ({}, {'k': 'v'})):
434
            json_data, ip, success, kwargs = args
435
            self.client.floating_ips_post(*args[:3], **kwargs)
436
            if json_data:
437
                json_data = dumps(json_data)
438
                self.assertEqual(SH.mock_calls[-2:], [
439
                    call('Content-Type', 'application/json'),
440
                    call('Content-Length', len(json_data))])
441
            expected = '' if not ip else '/%s' % ip
442
            self.assertEqual(post.mock_calls[-1], call(
443
                '/os-floating-ips%s' % expected,
444
                data=json_data, success=success,
445
                **kwargs))
446

    
447
    @patch('%s.delete' % rest_pkg, return_value=FR())
448
    def test_floating_ips_delete(self, delete):
449
        for args in product(
450
                ('', '192.193.194.195'),
451
                (204,),
452
                ({}, {'k': 'v'})):
453
            ip, success, kwargs = args
454
            r = self.client.floating_ips_delete(*args[:2], **kwargs)
455
            self.assertTrue(isinstance(r, FR))
456
            expected = '' if not ip else '/%s' % ip
457
            self.assertEqual(delete.mock_calls[-1], call(
458
                '/os-floating-ips%s' % expected, success=success, **kwargs))
459

    
460

    
461
class ComputeClient(TestCase):
462

    
463
    def assert_dicts_are_equal(self, d1, d2):
464
        for k, v in d1.items():
465
            self.assertTrue(k in d2)
466
            if isinstance(v, dict):
467
                self.assert_dicts_are_equal(v, d2[k])
468
            else:
469
                self.assertEqual(unicode(v), unicode(d2[k]))
470

    
471
    """Set up a Cyclades thorough test"""
472
    def setUp(self):
473
        self.url = 'http://cyclades.example.com'
474
        self.token = 'cyc14d3s70k3n'
475
        self.client = compute.ComputeClient(self.url, self.token)
476

    
477
    def tearDown(self):
478
        FR.status_code = 200
479
        FR.json = vm_recv
480

    
481
    @patch(
482
        '%s.get_image_details' % compute_pkg,
483
        return_value=img_recv['image'])
484
    def test_create_server(self, GID):
485
        with patch.object(
486
                compute.ComputeClient, 'servers_post',
487
                side_effect=ClientError(
488
                    'REQUEST ENTITY TOO LARGE',
489
                    status=403)):
490
            self.assertRaises(
491
                ClientError,
492
                self.client.create_server,
493
                vm_name, fid, img_ref)
494

    
495
        with patch.object(
496
                compute.ComputeClient, 'servers_post',
497
                return_value=FR()) as post:
498
            r = self.client.create_server(vm_name, fid, img_ref)
499
            self.assertEqual(r, FR.json['server'])
500
            self.assertEqual(GID.mock_calls[-1], call(img_ref))
501
            self.assertEqual(post.mock_calls[-1], call(json_data=vm_send))
502
            prsn = 'Personality string (does not work with real servers)'
503
            self.client.create_server(vm_name, fid, img_ref, prsn)
504
            expected = dict(server=dict(vm_send['server']))
505
            expected['server']['personality'] = prsn
506
            self.assertEqual(post.mock_calls[-1], call(json_data=expected))
507

    
508
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
509
    def test_list_servers(self, SG):
510
        FR.json = vm_list
511
        for detail in (False, True):
512
            r = self.client.list_servers(detail)
513
            self.assertEqual(SG.mock_calls[-1], call(
514
                command='detail' if detail else ''))
515
            for i, vm in enumerate(vm_list['servers']):
516
                self.assert_dicts_are_equal(r[i], vm)
517
            self.assertEqual(i + 1, len(r))
518

    
519
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
520
    def test_get_server_details(self, SG):
521
        vm_id = vm_recv['server']['id']
522
        r = self.client.get_server_details(vm_id)
523
        SG.assert_called_once_with(vm_id)
524
        self.assert_dicts_are_equal(r, vm_recv['server'])
525

    
526
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
527
    def test_update_server_name(self, SP):
528
        vm_id = vm_recv['server']['id']
529
        new_name = vm_name + '_new'
530
        self.client.update_server_name(vm_id, new_name)
531
        SP.assert_called_once_with(vm_id, json_data=dict(
532
            server=dict(name=new_name)))
533

    
534
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
535
    def test_reboot_server(self, SP):
536
        vm_id = vm_recv['server']['id']
537
        for hard in (None, True):
538
            self.client.reboot_server(vm_id, hard=hard)
539
            self.assertEqual(SP.mock_calls[-1], call(
540
                vm_id, 'action',
541
                json_data=dict(reboot=dict(type='HARD' if hard else 'SOFT'))))
542

    
543
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
544
    def test_resize_server(self, SP):
545
        vm_id, flavor = vm_recv['server']['id'], flavor_list['flavors'][1]
546
        self.client.resize_server(vm_id, flavor['id'])
547
        exp = dict(resize=dict(flavorRef=flavor['id']))
548
        SP.assert_called_once_with(vm_id, 'action', json_data=exp)
549

    
550
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
551
    def test_create_server_metadata(self, SP):
552
        vm_id = vm_recv['server']['id']
553
        metadata = dict(m1='v1', m2='v2', m3='v3')
554
        FR.json = dict(meta=vm_recv['server'])
555
        for k, v in metadata.items():
556
            r = self.client.create_server_metadata(vm_id, k, v)
557
            self.assert_dicts_are_equal(r, vm_recv['server'])
558
            self.assertEqual(SP.mock_calls[-1], call(
559
                vm_id, 'metadata/%s' % k,
560
                json_data=dict(meta={k: v}), success=201))
561

    
562
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
563
    def test_get_server_metadata(self, SG):
564
        vm_id = vm_recv['server']['id']
565
        metadata = dict(m1='v1', m2='v2', m3='v3')
566
        FR.json = dict(metadata=metadata)
567
        r = self.client.get_server_metadata(vm_id)
568
        FR.json = dict(meta=metadata)
569
        SG.assert_called_once_with(vm_id, '/metadata')
570
        self.assert_dicts_are_equal(r, metadata)
571

    
572
        for k, v in metadata.items():
573
            FR.json = dict(meta={k: v})
574
            r = self.client.get_server_metadata(vm_id, k)
575
            self.assert_dicts_are_equal(r, {k: v})
576
            self.assertEqual(
577
                SG.mock_calls[-1], call(vm_id, '/metadata/%s' % k))
578

    
579
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
580
    def test_update_server_metadata(self, SP):
581
        vm_id = vm_recv['server']['id']
582
        metadata = dict(m1='v1', m2='v2', m3='v3')
583
        FR.json = dict(metadata=metadata)
584
        r = self.client.update_server_metadata(vm_id, **metadata)
585
        self.assert_dicts_are_equal(r, metadata)
586
        SP.assert_called_once_with(
587
            vm_id, 'metadata',
588
            json_data=dict(metadata=metadata), success=201)
589

    
590
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
591
    def test_delete_server_metadata(self, SD):
592
        vm_id = vm_recv['server']['id']
593
        key = 'metakey'
594
        self.client.delete_server_metadata(vm_id, key)
595
        SD.assert_called_once_with(vm_id, 'metadata/' + key)
596

    
597
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
598
    def test_list_flavors(self, FG):
599
        FR.json = flavor_list
600
        for cmd in ('', 'detail'):
601
            r = self.client.list_flavors(detail=(cmd == 'detail'))
602
            self.assertEqual(FG.mock_calls[-1], call(command=cmd))
603
            self.assertEqual(r, flavor_list['flavors'])
604

    
605
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
606
    def test_get_flavor_details(self, FG):
607
        FR.json = dict(flavor=flavor_list['flavors'][0])
608
        r = self.client.get_flavor_details(fid)
609
        FG.assert_called_once_with(fid)
610
        self.assert_dicts_are_equal(r, flavor_list['flavors'][0])
611

    
612
    @patch('%s.images_get' % compute_pkg, return_value=FR())
613
    def test_list_images(self, IG):
614
        FR.json = img_list
615
        for cmd in ('', 'detail'):
616
            r = self.client.list_images(detail=(cmd == 'detail'))
617
            self.assertEqual(IG.mock_calls[-1], call(command=cmd))
618
            expected = img_list['images']
619
            for i in range(len(r)):
620
                self.assert_dicts_are_equal(expected[i], r[i])
621

    
622
    @patch('%s.images_get' % compute_pkg, return_value=FR())
623
    def test_get_image_details(self, IG):
624
        FR.json = img_recv
625
        r = self.client.get_image_details(img_ref)
626
        IG.assert_called_once_with(img_ref)
627
        self.assert_dicts_are_equal(r, img_recv['image'])
628

    
629
    @patch('%s.images_get' % compute_pkg, return_value=FR())
630
    def test_get_image_metadata(self, IG):
631
        for key in ('', '50m3k3y'):
632
            FR.json = dict(meta=img_recv['image']) if (
633
                key) else dict(metadata=img_recv['image'])
634
            r = self.client.get_image_metadata(img_ref, key)
635
            self.assertEqual(IG.mock_calls[-1], call(
636
                '%s' % img_ref,
637
                '/metadata%s' % (('/%s' % key) if key else '')))
638
            self.assert_dicts_are_equal(img_recv['image'], r)
639

    
640
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
641
    def test_delete_server(self, SD):
642
        vm_id = vm_recv['server']['id']
643
        self.client.delete_server(vm_id)
644
        SD.assert_called_once_with(vm_id)
645

    
646
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
647
    def test_delete_image(self, ID):
648
        self.client.delete_image(img_ref)
649
        ID.assert_called_once_with(img_ref)
650

    
651
    @patch('%s.images_put' % compute_pkg, return_value=FR())
652
    def test_create_image_metadata(self, IP):
653
        (key, val) = ('k1', 'v1')
654
        FR.json = dict(meta=img_recv['image'])
655
        r = self.client.create_image_metadata(img_ref, key, val)
656
        IP.assert_called_once_with(
657
            img_ref, 'metadata/%s' % key,
658
            json_data=dict(meta={key: val}))
659
        self.assert_dicts_are_equal(r, img_recv['image'])
660

    
661
    @patch('%s.images_post' % compute_pkg, return_value=FR())
662
    def test_update_image_metadata(self, IP):
663
        metadata = dict(m1='v1', m2='v2', m3='v3')
664
        FR.json = dict(metadata=metadata)
665
        r = self.client.update_image_metadata(img_ref, **metadata)
666
        IP.assert_called_once_with(
667
            img_ref, 'metadata',
668
            json_data=dict(metadata=metadata))
669
        self.assert_dicts_are_equal(r, metadata)
670

    
671
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
672
    def test_delete_image_metadata(self, ID):
673
        key = 'metakey'
674
        self.client.delete_image_metadata(img_ref, key)
675
        ID.assert_called_once_with(img_ref, '/metadata/%s' % key)
676

    
677
    @patch('%s.floating_ip_pools_get' % compute_pkg, return_value=FR())
678
    def test_get_floating_ip_pools(self, get):
679
        tid = 't3n@nt_1d'
680
        r = self.client.get_floating_ip_pools(tid)
681
        self.assert_dicts_are_equal(r, FR.json)
682
        self.assertEqual(get.mock_calls[-1], call(tid))
683

    
684
    @patch('%s.floating_ips_get' % compute_pkg, return_value=FR())
685
    def test_get_floating_ips(self, get):
686
        tid = 't3n@nt_1d'
687
        r = self.client.get_floating_ips(tid)
688
        self.assert_dicts_are_equal(r, FR.json)
689
        self.assertEqual(get.mock_calls[-1], call(tid))
690

    
691
    @patch('%s.floating_ips_post' % compute_pkg, return_value=FR())
692
    def test_alloc_floating_ip(self, post):
693
        FR.json = dict(floating_ip=dict(
694
            fixed_ip='fip',
695
            id=1,
696
            instance_id='lala',
697
            ip='102.0.0.1',
698
            pool='pisine'))
699
        for args in product(
700
                ('t1', 't2'),
701
                (None, 'pisine')):
702
            r = self.client.alloc_floating_ip(*args)
703
            tenant_id, pool = args
704
            self.assert_dicts_are_equal(r, FR.json['floating_ip'])
705
            expected = dict(pool=pool) if pool else dict()
706
            self.assertEqual(post.mock_calls[-1], call(tenant_id, expected))
707

    
708
    @patch('%s.floating_ips_get' % compute_pkg, return_value=FR())
709
    def test_get_floating_ip(self, get):
710
        FR.json = dict(floating_ips=[dict(
711
            fixed_ip='fip',
712
            id=1,
713
            instance_id='lala',
714
            ip='102.0.0.1',
715
            pool='pisine'), ])
716
        for args in product(
717
                ('t1', 't2'),
718
                (None, 'fip')):
719
            r = self.client.get_floating_ip(*args)
720
            tenant_id, fip = args
721
            self.assertEqual(r, FR.json['floating_ips'])
722
            self.assertEqual(get.mock_calls[-1], call(tenant_id, fip))
723

    
724
    @patch('%s.floating_ips_delete' % compute_pkg, return_value=FR())
725
    def test_delete_floating_ip(self, delete):
726
        for args in product(
727
                ('t1', 't2'),
728
                (None, 'fip')):
729
            r = self.client.delete_floating_ip(*args)
730
            tenant_id, fip = args
731
            self.assertEqual(r, FR.headers)
732
            self.assertEqual(delete.mock_calls[-1], call(tenant_id, fip))
733

    
734

    
735
if __name__ == '__main__':
736
    from sys import argv
737
    from kamaki.clients.test import runTestCase
738
    not_found = True
739
    if not argv[1:] or argv[1] == 'ComputeClient':
740
        not_found = False
741
        runTestCase(ComputeClient, 'Compute Client', argv[2:])
742
    if not argv[1:] or argv[1] == 'ComputeRest':
743
        not_found = False
744
        runTestCase(ComputeRestClient, 'ComputeRest Client', argv[2:])
745
    if not_found:
746
        print('TestCase %s not found' % argv[1])