Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / test.py @ 5ed87051

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

    
40
from kamaki.clients import ClientError, compute
41

    
42

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

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

    
101

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

    
110

    
111
class ComputeRestClient(TestCase):
112

    
113
    """Set up a ComputesRest thorough test"""
114
    def setUp(self):
115
        self.url = 'http://cyclades.example.com'
116
        self.token = 'cyc14d3s70k3n'
117
        self.client = compute.ComputeRestClient(self.url, self.token)
118

    
119
    def tearDown(self):
120
        FR.json = vm_recv
121

    
122
    @patch('%s.get' % rest_pkg, return_value=FR())
123
    def test_limits_get(self, get):
124
        self.client.limits_get(success='some_val')
125
        get.assert_called_once_with('/limits', success='some_val')
126

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

    
160
            if not i % 1000:
161
                stdout.write('\b' * len(num_of_its))
162
                num_of_its = '%s' % i
163
                stdout.write(num_of_its)
164
                stdout.flush()
165
        print ('\b' * len(num_of_its)) + ('%s' % i)
166

    
167
    def test_servers_get(self):
168
        params = dict(
169
            changes_since=('changes-since', None),
170
            image=('image', None),
171
            flavor=('flavor', None),
172
            name=('name', None),
173
            marker=('marker', None),
174
            limit=('limit', None),
175
            status=('status', None),
176
            host=('host', None))
177
        self._test_get('servers', params)
178

    
179
    def test_flavors_get(self):
180
        params = dict(
181
            changes_since=('changes-since', None),
182
            minDisk=('minDisk', None),
183
            minRam=('minRam', None),
184
            marker=('marker', None),
185
            limit=('limit', None))
186
        self._test_get('flavors', params)
187

    
188
    def test_images_get(self):
189
        param = dict(
190
            changes_since=('changes-since', None),
191
            server_name=('server', None),
192
            name=('name', None),
193
            status=('status', None),
194
            marker=('marker', None),
195
            limit=('limit', None),
196
            type=('type', None))
197
        self._test_get('images', param)
198

    
199
    @patch('%s.delete' % rest_pkg, return_value=FR())
200
    def _test_delete(self, service, delete):
201
        for args in product(
202
                ('', '%s_id' % service),
203
                ('', 'cmd'),
204
                (204, 208),
205
                ({}, {'k': 'v'})):
206
            (srv_id, command, success, kwargs) = args
207
            method = getattr(self.client, '%s_delete' % service)
208
            method(*args[:3], **kwargs)
209
            vm_str = '/%s' % srv_id if srv_id else ''
210
            cmd_str = '/%s' % command if command else ''
211
            self.assertEqual(delete.mock_calls[-1], call(
212
                '/%s%s%s' % (service, vm_str, cmd_str),
213
                success=success,
214
                **kwargs))
215

    
216
    def test_servers_delete(self):
217
        self._test_delete('servers')
218

    
219
    def test_images_delete(self):
220
        self._test_delete('images')
221

    
222
    @patch('%s.set_header' % rest_pkg)
223
    @patch('%s.post' % rest_pkg, return_value=FR())
224
    def _test_post(self, service, post, SH):
225
        for args in product(
226
                ('', '%s_id' % service),
227
                ('', 'cmd'),
228
                (None, [dict(json="data"), dict(data="json")]),
229
                (202, 204),
230
                ({}, {'k': 'v'})):
231
            (srv_id, command, json_data, success, kwargs) = args
232
            method = getattr(self.client, '%s_post' % service)
233
            method(*args[:4], **kwargs)
234
            vm_str = '/%s' % srv_id if srv_id else ''
235
            cmd_str = '/%s' % command if command else ''
236
            if json_data:
237
                json_data = dumps(json_data)
238
                self.assertEqual(SH.mock_calls[-2:], [
239
                    call('Content-Type', 'application/json'),
240
                    call('Content-Length', len(json_data))])
241
            self.assertEqual(post.mock_calls[-1], call(
242
                '/%s%s%s' % (service, vm_str, cmd_str),
243
                data=json_data, success=success,
244
                **kwargs))
245

    
246
    def test_servers_post(self):
247
        self._test_post('servers')
248

    
249
    def test_images_post(self):
250
        self._test_post('images')
251

    
252
    @patch('%s.set_header' % rest_pkg)
253
    @patch('%s.put' % rest_pkg, return_value=FR())
254
    def _test_put(self, service, put, SH):
255
        for args in product(
256
                ('', '%s_id' % service),
257
                ('', 'cmd'),
258
                (None, [dict(json="data"), dict(data="json")]),
259
                (204, 504),
260
                ({}, {'k': 'v'})):
261
            (server_id, command, json_data, success, kwargs) = args
262
            method = getattr(self.client, '%s_put' % service)
263
            method(*args[:4], **kwargs)
264
            vm_str = '/%s' % server_id if server_id else ''
265
            cmd_str = '/%s' % command if command else ''
266
            if json_data:
267
                json_data = dumps(json_data)
268
                self.assertEqual(SH.mock_calls[-2:], [
269
                    call('Content-Type', 'application/json'),
270
                    call('Content-Length', len(json_data))])
271
            self.assertEqual(put.mock_calls[-1], call(
272
                '/%s%s%s' % (service, vm_str, cmd_str),
273
                data=json_data, success=success,
274
                **kwargs))
275

    
276
    def test_servers_put(self):
277
        self._test_put('servers')
278

    
279
    def test_images_put(self):
280
        self._test_put('images')
281

    
282
    @patch('%s.get' % rest_pkg, return_value=FR())
283
    def test_floating_ip_pools_get(self, get):
284
        for args in product(
285
                ('tenant1', 'tenant2'),
286
                (200, 204),
287
                ({}, {'k': 'v'})):
288
            tenant_id, success, kwargs = args
289
            r = self.client.floating_ip_pools_get(tenant_id, success, **kwargs)
290
            self.assertTrue(isinstance(r, FR))
291
            self.assertEqual(get.mock_calls[-1], call(
292
                '/%s/os-floating-ip-pools' % tenant_id,
293
                success=success, **kwargs))
294

    
295
    @patch('%s.get' % rest_pkg, return_value=FR())
296
    def test_floating_ips_get(self, get):
297
        for args in product(
298
                ('tenant1', 'tenant2'),
299
                ('', '192.193.194.195'),
300
                (200, 204),
301
                ({}, {'k': 'v'})):
302
            tenant_id, ip, success, kwargs = args
303
            r = self.client.floating_ips_get(*args[:3], **kwargs)
304
            self.assertTrue(isinstance(r, FR))
305
            expected = '' if not ip else '/%s' % ip
306
            self.assertEqual(get.mock_calls[-1], call(
307
                '/%s/os-floating-ips%s' % (tenant_id, expected),
308
                success=success, **kwargs))
309

    
310
    @patch('%s.set_header' % rest_pkg)
311
    @patch('%s.post' % rest_pkg, return_value=FR())
312
    def test_floating_ips_post(self, post, SH):
313
        for args in product(
314
                ('tenant1', 'tenant2'),
315
                (None, [dict(json="data"), dict(data="json")]),
316
                ('', '192.193.194.195'),
317
                (202, 204),
318
                ({}, {'k': 'v'})):
319
            (tenant_id, json_data, ip, success, kwargs) = args
320
            self.client.floating_ips_post(*args[:4], **kwargs)
321
            if json_data:
322
                json_data = dumps(json_data)
323
                self.assertEqual(SH.mock_calls[-2:], [
324
                    call('Content-Type', 'application/json'),
325
                    call('Content-Length', len(json_data))])
326
            expected = '' if not ip else '/%s' % ip
327
            self.assertEqual(post.mock_calls[-1], call(
328
                '/%s/os-floating-ips%s' % (tenant_id, expected),
329
                data=json_data, success=success,
330
                **kwargs))
331

    
332
    @patch('%s.delete' % rest_pkg, return_value=FR())
333
    def test_floating_ips_delete(self, delete):
334
        for args in product(
335
                ('tenant1', 'tenant2'),
336
                ('', '192.193.194.195'),
337
                (204,),
338
                ({}, {'k': 'v'})):
339
            tenant_id, ip, success, kwargs = args
340
            r = self.client.floating_ips_delete(*args[:3], **kwargs)
341
            self.assertTrue(isinstance(r, FR))
342
            expected = '' if not ip else '/%s' % ip
343
            self.assertEqual(delete.mock_calls[-1], call(
344
                '/%s/os-floating-ips%s' % (tenant_id, expected),
345
                success=success, **kwargs))
346

    
347

    
348
class ComputeClient(TestCase):
349

    
350
    def assert_dicts_are_equal(self, d1, d2):
351
        for k, v in d1.items():
352
            self.assertTrue(k in d2)
353
            if isinstance(v, dict):
354
                self.assert_dicts_are_equal(v, d2[k])
355
            else:
356
                self.assertEqual(unicode(v), unicode(d2[k]))
357

    
358
    """Set up a Cyclades thorough test"""
359
    def setUp(self):
360
        self.url = 'http://cyclades.example.com'
361
        self.token = 'cyc14d3s70k3n'
362
        self.client = compute.ComputeClient(self.url, self.token)
363

    
364
    def tearDown(self):
365
        FR.status_code = 200
366
        FR.json = vm_recv
367

    
368
    @patch(
369
        '%s.get_image_details' % compute_pkg,
370
        return_value=img_recv['image'])
371
    def test_create_server(self, GID):
372
        with patch.object(
373
                compute.ComputeClient, 'servers_post',
374
                side_effect=ClientError(
375
                    'REQUEST ENTITY TOO LARGE',
376
                    status=403)):
377
            self.assertRaises(
378
                ClientError,
379
                self.client.create_server,
380
                vm_name, fid, img_ref)
381

    
382
        with patch.object(
383
                compute.ComputeClient, 'servers_post',
384
                return_value=FR()) as post:
385
            r = self.client.create_server(vm_name, fid, img_ref)
386
            self.assertEqual(r, FR.json['server'])
387
            self.assertEqual(GID.mock_calls[-1], call(img_ref))
388
            self.assertEqual(post.mock_calls[-1], call(json_data=vm_send))
389
            prsn = 'Personality string (does not work with real servers)'
390
            self.client.create_server(vm_name, fid, img_ref, prsn)
391
            expected = dict(server=dict(vm_send['server']))
392
            expected['server']['personality'] = prsn
393
            self.assertEqual(post.mock_calls[-1], call(json_data=expected))
394

    
395
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
396
    def test_list_servers(self, SG):
397
        FR.json = vm_list
398
        for detail in (False, True):
399
            r = self.client.list_servers(detail)
400
            self.assertEqual(SG.mock_calls[-1], call(
401
                command='detail' if detail else ''))
402
            for i, vm in enumerate(vm_list['servers']):
403
                self.assert_dicts_are_equal(r[i], vm)
404
            self.assertEqual(i + 1, len(r))
405

    
406
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
407
    def test_get_server_details(self, SG):
408
        vm_id = vm_recv['server']['id']
409
        r = self.client.get_server_details(vm_id)
410
        SG.assert_called_once_with(vm_id)
411
        self.assert_dicts_are_equal(r, vm_recv['server'])
412

    
413
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
414
    def test_update_server_name(self, SP):
415
        vm_id = vm_recv['server']['id']
416
        new_name = vm_name + '_new'
417
        self.client.update_server_name(vm_id, new_name)
418
        SP.assert_called_once_with(vm_id, json_data=dict(
419
            server=dict(name=new_name)))
420

    
421
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
422
    def test_reboot_server(self, SP):
423
        vm_id = vm_recv['server']['id']
424
        for hard in (None, True):
425
            self.client.reboot_server(vm_id, hard=hard)
426
            self.assertEqual(SP.mock_calls[-1], call(
427
                vm_id, 'action',
428
                json_data=dict(reboot=dict(type='HARD' if hard else 'SOFT'))))
429

    
430
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
431
    def test_resize_server(self, SP):
432
        vm_id, flavor = vm_recv['server']['id'], flavor_list['flavors'][1]
433
        self.client.resize_server(vm_id, flavor['id'])
434
        exp = dict(resize=dict(flavorRef=flavor['id']))
435
        SP.assert_called_once_with(vm_id, 'action', json_data=exp)
436

    
437
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
438
    def test_create_server_metadata(self, SP):
439
        vm_id = vm_recv['server']['id']
440
        metadata = dict(m1='v1', m2='v2', m3='v3')
441
        FR.json = dict(meta=vm_recv['server'])
442
        for k, v in metadata.items():
443
            r = self.client.create_server_metadata(vm_id, k, v)
444
            self.assert_dicts_are_equal(r, vm_recv['server'])
445
            self.assertEqual(SP.mock_calls[-1], call(
446
                vm_id, 'metadata/%s' % k,
447
                json_data=dict(meta={k: v}), success=201))
448

    
449
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
450
    def test_get_server_metadata(self, SG):
451
        vm_id = vm_recv['server']['id']
452
        metadata = dict(m1='v1', m2='v2', m3='v3')
453
        FR.json = dict(metadata=metadata)
454
        r = self.client.get_server_metadata(vm_id)
455
        FR.json = dict(meta=metadata)
456
        SG.assert_called_once_with(vm_id, '/metadata')
457
        self.assert_dicts_are_equal(r, metadata)
458

    
459
        for k, v in metadata.items():
460
            FR.json = dict(meta={k: v})
461
            r = self.client.get_server_metadata(vm_id, k)
462
            self.assert_dicts_are_equal(r, {k: v})
463
            self.assertEqual(
464
                SG.mock_calls[-1], call(vm_id, '/metadata/%s' % k))
465

    
466
    @patch('%s.servers_post' % compute_pkg, return_value=FR())
467
    def test_update_server_metadata(self, SP):
468
        vm_id = vm_recv['server']['id']
469
        metadata = dict(m1='v1', m2='v2', m3='v3')
470
        FR.json = dict(metadata=metadata)
471
        r = self.client.update_server_metadata(vm_id, **metadata)
472
        self.assert_dicts_are_equal(r, metadata)
473
        SP.assert_called_once_with(
474
            vm_id, 'metadata',
475
            json_data=dict(metadata=metadata), success=201)
476

    
477
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
478
    def test_delete_server_metadata(self, SD):
479
        vm_id = vm_recv['server']['id']
480
        key = 'metakey'
481
        self.client.delete_server_metadata(vm_id, key)
482
        SD.assert_called_once_with(vm_id, 'metadata/' + key)
483

    
484
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
485
    def test_list_flavors(self, FG):
486
        FR.json = flavor_list
487
        for cmd in ('', 'detail'):
488
            r = self.client.list_flavors(detail=(cmd == 'detail'))
489
            self.assertEqual(FG.mock_calls[-1], call(command=cmd))
490
            self.assertEqual(r, flavor_list['flavors'])
491

    
492
    @patch('%s.flavors_get' % compute_pkg, return_value=FR())
493
    def test_get_flavor_details(self, FG):
494
        FR.json = dict(flavor=flavor_list['flavors'][0])
495
        r = self.client.get_flavor_details(fid)
496
        FG.assert_called_once_with(fid)
497
        self.assert_dicts_are_equal(r, flavor_list['flavors'][0])
498

    
499
    @patch('%s.images_get' % compute_pkg, return_value=FR())
500
    def test_list_images(self, IG):
501
        FR.json = img_list
502
        for cmd in ('', 'detail'):
503
            r = self.client.list_images(detail=(cmd == 'detail'))
504
            self.assertEqual(IG.mock_calls[-1], call(command=cmd))
505
            expected = img_list['images']
506
            for i in range(len(r)):
507
                self.assert_dicts_are_equal(expected[i], r[i])
508

    
509
    @patch('%s.images_get' % compute_pkg, return_value=FR())
510
    def test_get_image_details(self, IG):
511
        FR.json = img_recv
512
        r = self.client.get_image_details(img_ref)
513
        IG.assert_called_once_with(img_ref)
514
        self.assert_dicts_are_equal(r, img_recv['image'])
515

    
516
    @patch('%s.images_get' % compute_pkg, return_value=FR())
517
    def test_get_image_metadata(self, IG):
518
        for key in ('', '50m3k3y'):
519
            FR.json = dict(meta=img_recv['image']) if (
520
                key) else dict(metadata=img_recv['image'])
521
            r = self.client.get_image_metadata(img_ref, key)
522
            self.assertEqual(IG.mock_calls[-1], call(
523
                '%s' % img_ref,
524
                '/metadata%s' % (('/%s' % key) if key else '')))
525
            self.assert_dicts_are_equal(img_recv['image'], r)
526

    
527
    @patch('%s.servers_delete' % compute_pkg, return_value=FR())
528
    def test_delete_server(self, SD):
529
        vm_id = vm_recv['server']['id']
530
        self.client.delete_server(vm_id)
531
        SD.assert_called_once_with(vm_id)
532

    
533
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
534
    def test_delete_image(self, ID):
535
        self.client.delete_image(img_ref)
536
        ID.assert_called_once_with(img_ref)
537

    
538
    @patch('%s.images_put' % compute_pkg, return_value=FR())
539
    def test_create_image_metadata(self, IP):
540
        (key, val) = ('k1', 'v1')
541
        FR.json = dict(meta=img_recv['image'])
542
        r = self.client.create_image_metadata(img_ref, key, val)
543
        IP.assert_called_once_with(
544
            img_ref, 'metadata/%s' % key,
545
            json_data=dict(meta={key: val}))
546
        self.assert_dicts_are_equal(r, img_recv['image'])
547

    
548
    @patch('%s.images_post' % compute_pkg, return_value=FR())
549
    def test_update_image_metadata(self, IP):
550
        metadata = dict(m1='v1', m2='v2', m3='v3')
551
        FR.json = dict(metadata=metadata)
552
        r = self.client.update_image_metadata(img_ref, **metadata)
553
        IP.assert_called_once_with(
554
            img_ref, 'metadata',
555
            json_data=dict(metadata=metadata))
556
        self.assert_dicts_are_equal(r, metadata)
557

    
558
    @patch('%s.images_delete' % compute_pkg, return_value=FR())
559
    def test_delete_image_metadata(self, ID):
560
        key = 'metakey'
561
        self.client.delete_image_metadata(img_ref, key)
562
        ID.assert_called_once_with(img_ref, '/metadata/%s' % key)
563

    
564
    @patch('%s.floating_ip_pools_get' % compute_pkg, return_value=FR())
565
    def test_get_floating_ip_pools(self, get):
566
        tid = 't3n@nt_1d'
567
        r = self.client.get_floating_ip_pools(tid)
568
        self.assert_dicts_are_equal(r, FR.json)
569
        self.assertEqual(get.mock_calls[-1], call(tid))
570

    
571
    @patch('%s.floating_ips_get' % compute_pkg, return_value=FR())
572
    def test_get_floating_ips(self, get):
573
        tid = 't3n@nt_1d'
574
        r = self.client.get_floating_ips(tid)
575
        self.assert_dicts_are_equal(r, FR.json)
576
        self.assertEqual(get.mock_calls[-1], call(tid))
577

    
578
    @patch('%s.floating_ips_post' % compute_pkg, return_value=FR())
579
    def test_alloc_floating_ip(self, post):
580
        FR.json = dict(floating_ip=dict(
581
            fixed_ip='fip',
582
            id=1,
583
            instance_id='lala',
584
            ip='102.0.0.1',
585
            pool='pisine'))
586
        for args in product(
587
                ('t1', 't2'),
588
                (None, 'pisine')):
589
            r = self.client.alloc_floating_ip(*args)
590
            tenant_id, pool = args
591
            self.assert_dicts_are_equal(r, FR.json['floating_ip'])
592
            expected = dict(pool=pool) if pool else dict()
593
            self.assertEqual(post.mock_calls[-1], call(tenant_id, expected))
594

    
595
    @patch('%s.floating_ips_get' % compute_pkg, return_value=FR())
596
    def test_get_floating_ip(self, get):
597
        FR.json = dict(floating_ips=[dict(
598
            fixed_ip='fip',
599
            id=1,
600
            instance_id='lala',
601
            ip='102.0.0.1',
602
            pool='pisine'), ])
603
        for args in product(
604
                ('t1', 't2'),
605
                (None, 'fip')):
606
            r = self.client.get_floating_ip(*args)
607
            tenant_id, fip = args
608
            self.assertEqual(r, FR.json['floating_ips'])
609
            self.assertEqual(get.mock_calls[-1], call(tenant_id, fip))
610

    
611
    @patch('%s.floating_ips_delete' % compute_pkg, return_value=FR())
612
    def test_delete_floating_ip(self, delete):
613
        for args in product(
614
                ('t1', 't2'),
615
                (None, 'fip')):
616
            r = self.client.delete_floating_ip(*args)
617
            tenant_id, fip = args
618
            self.assertEqual(r, FR.headers)
619
            self.assertEqual(delete.mock_calls[-1], call(tenant_id, fip))
620

    
621

    
622
if __name__ == '__main__':
623
    from sys import argv
624
    from kamaki.clients.test import runTestCase
625
    not_found = True
626
    if not argv[1:] or argv[1] == 'ComputeClient':
627
        not_found = False
628
        runTestCase(ComputeClient, 'Compute Client', argv[2:])
629
    if not argv[1:] or argv[1] == 'ComputeRest':
630
        not_found = False
631
        runTestCase(ComputeRestClient, 'ComputeRest Client', argv[2:])
632
    if not_found:
633
        print('TestCase %s not found' % argv[1])