Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / test.py @ 304a92dc

History | View | Annotate | Download (26.4 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, Mock, call
35
from unittest import TestCase
36
from json import loads
37

    
38
from kamaki.clients import Client, ClientError
39
from kamaki.clients.cyclades import CycladesClient
40
from kamaki.clients.cyclades_rest_api import CycladesClientApi
41

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

    
116

    
117
class FR(object):
118
    """FR stands for Fake Response"""
119
    json = vm_recv
120
    headers = {}
121
    content = json
122
    status = None
123
    status_code = 200
124

    
125
    def release(self):
126
        pass
127

    
128
khttp = 'kamaki.clients.connection.kamakicon.KamakiHTTPConnection'
129
cyclades_pkg = 'kamaki.clients.cyclades.CycladesClient'
130

    
131

    
132
class Cyclades(TestCase):
133

    
134
    def assert_dicts_are_equal(self, d1, d2):
135
        for k, v in d1.items():
136
            self.assertTrue(k in d2)
137
            if isinstance(v, dict):
138
                self.assert_dicts_are_equal(v, d2[k])
139
            else:
140
                self.assertEqual(unicode(v), unicode(d2[k]))
141

    
142
    """Set up a Cyclades thorough test"""
143
    def setUp(self):
144
        self.url = 'http://cyclades.example.com'
145
        self.token = 'cyc14d3s70k3n'
146
        self.client = CycladesClient(self.url, self.token)
147
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
148
        self.C = KamakiHTTPConnection
149

    
150
    def tearDown(self):
151
        FR.status_code = 200
152
        FR.json = vm_recv
153

    
154
    """
155
    def test_create_server(self):
156
        self.client.get_image_details = Mock(return_value=img_recv['image'])
157
        with patch.object(Client, 'request', side_effect=ClientError(
158
                'REQUEST ENTITY TOO LARGE',
159
                status=403)):
160
            self.assertRaises(
161
                ClientError,
162
                self.client.create_server,
163
                vm_name, fid, img_ref)
164

165
        with patch.object(
166
                self.C,
167
                'perform_request',
168
                return_value=FR()) as perform_req:
169
            self.assertRaises(
170
                ClientError,
171
                self.client.create_server,
172
                vm_name, fid, img_ref)
173
            FR.status_code = 202
174
            r = self.client.create_server(vm_name, fid, img_ref)
175
            self.assertEqual(self.client.http_client.url, self.url)
176
            self.assertEqual(self.client.http_client.path, '/servers')
177
            (method, data, a_headers, a_params) = perform_req.call_args[0]
178
            self.assert_dicts_are_equal(loads(data), vm_send)
179
            self.assert_dicts_are_equal(r, vm_recv['server'])
180
            prsn = 'Personality string (does not work with real servers)'
181
            self.client.create_server(vm_name, fid, img_ref, prsn)
182
            (method, data, a_headers, a_params) = perform_req.call_args[0]
183
            data = loads(data)
184
            self.assertTrue('personality' in data['server'])
185
            self.assertEqual(prsn, data['server']['personality'])
186

187
    def test_list_servers(self):
188
        FR.json = vm_list
189
        with patch.object(
190
                self.C,
191
                'perform_request',
192
                return_value=FR()) as perform_req:
193
            r = self.client.list_servers()
194
            self.assertEqual(self.client.http_client.url, self.url)
195
            self.assertEqual(self.client.http_client.path, '/servers')
196
            (method, data, a_headers, a_params) = perform_req.call_args[0]
197
            self.assert_dicts_are_equal(dict(values=r), vm_list['servers'])
198
            r = self.client.list_servers(detail=True)
199
            self.assertEqual(self.client.http_client.url, self.url)
200
            self.assertEqual(self.client.http_client.path, '/servers/detail')
201
        with patch.object(
202
                CycladesClientApi,
203
                'servers_get',
204
                return_value=FR()) as servers_get:
205
            self.client.list_servers(changes_since=True)
206
            self.assertTrue(servers_get.call_args[1]['changes_since'])
207

208
    @patch('%s.perform_request' % khttp, return_value=FR())
209
    def test_get_server_details(self, PR):
210
        vm_id = vm_recv['server']['id']
211
        r = self.client.get_server_details(vm_id)
212
        self.assertEqual(self.client.http_client.url, self.url)
213
        self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
214
        self.assert_dicts_are_equal(r, vm_recv['server'])
215

216
    @patch('%s.perform_request' % khttp, return_value=FR())
217
    def test_update_server_name(self, PR):
218
        vm_id = vm_recv['server']['id']
219
        new_name = vm_name + '_new'
220
        FR.status_code = 204
221
        self.client.update_server_name(vm_id, new_name)
222
        self.assertEqual(self.client.http_client.url, self.url)
223
        self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
224
        (method, data, a_headers, a_params) = PR.call_args[0]
225
        self.assert_dicts_are_equal(
226
            dict(server=dict(name=new_name)),
227
            loads(data))
228

229
    @patch('%s.perform_request' % khttp, return_value=FR())
230
    def test_reboot_server(self, PR):
231
        vm_id = vm_recv['server']['id']
232
        FR.status_code = 202
233
        self.client.reboot_server(vm_id)
234
        self.assertEqual(self.client.http_client.url, self.url)
235
        self.assertEqual(
236
            self.client.http_client.path,
237
            '/servers/%s/action' % vm_id)
238
        (method, data, a_headers, a_params) = PR.call_args[0]
239
        self.assert_dicts_are_equal(
240
            dict(reboot=dict(type='SOFT')),
241
            loads(data))
242

243
    @patch('%s.perform_request' % khttp, return_value=FR())
244
    def test_create_server_metadata(self, PR):
245
        vm_id = vm_recv['server']['id']
246
        metadata = dict(m1='v1', m2='v2', m3='v3')
247
        FR.json = dict(meta=vm_recv['server'])
248
        self.assertRaises(
249
            ClientError,
250
            self.client.create_server_metadata,
251
            vm_id, 'key', 'value')
252
        FR.status_code = 201
253
        for k, v in metadata.items():
254
            r = self.client.create_server_metadata(vm_id, k, v)
255
            self.assertEqual(self.client.http_client.url, self.url)
256
            self.assertEqual(
257
                self.client.http_client.path,
258
                '/servers/%s/meta/%s' % (vm_id, k))
259
            (method, data, a_headers, a_params) = PR.call_args[0]
260
            self.assertEqual(dict(meta={k: v}), loads(data))
261
            self.assert_dicts_are_equal(r, vm_recv['server'])
262

263
    @patch('%s.perform_request' % khttp, return_value=FR())
264
    def test_get_server_metadata(self, PR):
265
        vm_id = vm_recv['server']['id']
266
        metadata = dict(m1='v1', m2='v2', m3='v3')
267
        FR.json = dict(metadata=dict(values=metadata))
268
        r = self.client.get_server_metadata(vm_id)
269
        self.assertEqual(self.client.http_client.url, self.url)
270
        self.assertEqual(
271
            self.client.http_client.path,
272
            '/servers/%s/meta' % vm_id)
273
        self.assert_dicts_are_equal(r, metadata)
274

275
        for k, v in metadata.items():
276
            FR.json = dict(meta={k: v})
277
            r = self.client.get_server_metadata(vm_id, k)
278
            self.assertEqual(self.client.http_client.url, self.url)
279
            self.assertEqual(
280
                self.client.http_client.path,
281
                '/servers/%s/meta/%s' % (vm_id, k))
282
            self.assert_dicts_are_equal(r, {k: v})
283

284
    @patch('%s.servers_post' % cyclades_pkg, return_value=FR())
285
    def test_update_server_metadata(self, servers_post):
286
        vm_id = vm_recv['server']['id']
287
        metadata = dict(m1='v1', m2='v2', m3='v3')
288
        FR.json = dict(metadata=metadata)
289
        r = self.client.update_server_metadata(vm_id, **metadata)
290
        self.assert_dicts_are_equal(r, metadata)
291
        (called_id, cmd) = servers_post.call_args[0]
292
        self.assertEqual(called_id, vm_id)
293
        self.assertEqual(cmd, 'meta')
294
        data = servers_post.call_args[1]['json_data']
295
        self.assert_dicts_are_equal(data, dict(metadata=metadata))
296

297
    @patch('%s.servers_delete' % cyclades_pkg, return_value=FR())
298
    def test_delete_server_metadata(self, servers_delete):
299
        vm_id = vm_recv['server']['id']
300
        key = 'metakey'
301
        self.client.delete_server_metadata(vm_id, key)
302
        self.assertEqual((vm_id, 'meta/' + key), servers_delete.call_args[0])
303

304
    @patch('%s.perform_request' % khttp, return_value=FR())
305
    def test_list_flavors(self, PR):
306
        FR.json = flavor_list
307
        r = self.client.list_flavors()
308
        self.assertEqual(self.client.http_client.url, self.url)
309
        self.assertEqual(self.client.http_client.path, '/flavors')
310
        (method, data, a_headers, a_params) = PR.call_args[0]
311
        self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
312
        r = self.client.list_flavors(detail=True)
313
        self.assertEqual(self.client.http_client.url, self.url)
314
        self.assertEqual(self.client.http_client.path, '/flavors/detail')
315

316
    @patch('%s.perform_request' % khttp, return_value=FR())
317
    def test_get_flavor_details(self, PR):
318
        FR.json = dict(flavor=flavor_list['flavors'])
319
        r = self.client.get_flavor_details(fid)
320
        self.assertEqual(self.client.http_client.url, self.url)
321
        self.assertEqual(self.client.http_client.path, '/flavors/%s' % fid)
322
        self.assert_dicts_are_equal(r, flavor_list['flavors'])
323

324
    @patch('%s.perform_request' % khttp, return_value=FR())
325
    def test_list_images(self, PR):
326
        FR.json = img_list
327
        r = self.client.list_images()
328
        self.assertEqual(self.client.http_client.url, self.url)
329
        self.assertEqual(self.client.http_client.path, '/images')
330
        expected = img_list['images']['values']
331
        for i in range(len(r)):
332
            self.assert_dicts_are_equal(expected[i], r[i])
333
        self.client.list_images(detail=True)
334
        self.assertEqual(self.client.http_client.url, self.url)
335
        self.assertEqual(self.client.http_client.path, '/images/detail')
336

337
    @patch('%s.perform_request' % khttp, return_value=FR())
338
    def test_get_image_details(self, PR):
339
        FR.json = img_recv
340
        r = self.client.get_image_details(img_ref)
341
        self.assertEqual(self.client.http_client.url, self.url)
342
        self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
343
        self.assert_dicts_are_equal(r, img_recv['image'])
344

345
    @patch('%s.images_get' % cyclades_pkg, return_value=FR())
346
    def test_get_image_metadata(self, IG):
347
        FR.json = dict(metadata=dict(values=img_recv['image']))
348
        r = self.client.get_image_metadata(img_ref)
349
        self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta'))
350
        self.assert_dicts_are_equal(img_recv['image'], r)
351
        FR.json = dict(meta=img_recv['image'])
352
        key = 'somekey'
353
        self.client.get_image_metadata(img_ref, key)
354
        self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta/%s' % key))
355

356
    @patch('%s.perform_request' % khttp, return_value=FR())
357
    def test_shutdown_server(self, PR):
358
        vm_id = vm_recv['server']['id']
359
        FR.status_code = 202
360
        self.client.shutdown_server(vm_id)
361
        self.assertEqual(self.client.http_client.url, self.url)
362
        self.assertEqual(
363
            self.client.http_client.path,
364
            '/servers/%s/action' % vm_id)
365
        self.assertEqual(
366
            PR.call_args[0],
367
            ('post',  '{"shutdown": {}}', {}, {}))
368

369
    @patch('%s.perform_request' % khttp, return_value=FR())
370
    def test_start_server(self, PR):
371
        vm_id = vm_recv['server']['id']
372
        FR.status_code = 202
373
        self.client.start_server(vm_id)
374
        self.assertEqual(self.client.http_client.url, self.url)
375
        self.assertEqual(
376
            self.client.http_client.path,
377
            '/servers/%s/action' % vm_id)
378
        self.assertEqual(PR.call_args[0], ('post',  '{"start": {}}', {}, {}))
379

380
    @patch('%s.perform_request' % khttp, return_value=FR())
381
    def test_get_server_console(self, PR):
382
        cnsl = dict(console=dict(info1='i1', info2='i2', info3='i3'))
383
        FR.json = cnsl
384
        vm_id = vm_recv['server']['id']
385
        r = self.client.get_server_console(vm_id)
386
        self.assertEqual(self.client.http_client.url, self.url)
387
        self.assertEqual(
388
            self.client.http_client.path,
389
            '/servers/%s/action' % vm_id)
390
        self.assert_dicts_are_equal(cnsl['console'], r)
391
        self.assertEqual(
392
            PR.call_args[0],
393
            ('post',  '{"console": {"type": "vnc"}}', {}, {}))
394

395
    def test_get_firewall_profile(self):
396
        vm_id = vm_recv['server']['id']
397
        v = 'Some profile'
398
        ret = {'attachments': {'values': [{'firewallProfile': v, 1:1}]}}
399
        with patch.object(
400
                CycladesClient,
401
                'get_server_details',
402
                return_value=ret) as GSD:
403
            r = self.client.get_firewall_profile(vm_id)
404
            self.assertEqual(r, v)
405
            self.assertEqual(GSD.call_args[0], (vm_id,))
406
            ret['attachments']['values'][0].pop('firewallProfile')
407
            self.assertRaises(
408
                ClientError,
409
                self.client.get_firewall_profile,
410
                vm_id)
411

412
    @patch('%s.perform_request' % khttp, return_value=FR())
413
    def test_set_firewall_profile(self, PR):
414
        vm_id = vm_recv['server']['id']
415
        v = 'Some profile'
416
        FR.status_code = 202
417
        self.client.set_firewall_profile(vm_id, v)
418
        self.assertEqual(self.client.http_client.url, self.url)
419
        self.assertEqual(
420
            self.client.http_client.path,
421
            '/servers/%s/action' % vm_id)
422
        self.assertEqual(PR.call_args[0], (
423
            'post',
424
            '{"firewallProfile": {"profile": "%s"}}' % v,
425
            {},
426
            {}))
427

428
    @patch('%s.perform_request' % khttp, return_value=FR())
429
    def test_get_server_stats(self, PR):
430
        vm_id = vm_recv['server']['id']
431
        stats = dict(stat1='v1', stat2='v2', stat3='v3', stat4='v4')
432
        FR.json = dict(stats=stats)
433
        r = self.client.get_server_stats(vm_id)
434
        self.assertEqual(self.client.http_client.url, self.url)
435
        self.assertEqual(
436
            self.client.http_client.path,
437
            '/servers/%s/stats' % vm_id)
438
        self.assert_dicts_are_equal(stats, r)
439

440
    @patch('%s.perform_request' % khttp, return_value=FR())
441
    def test_create_network(self, PR):
442
        net_name = net_send['network']['name']
443
        FR.json = net_recv
444
        FR.status_code = 202
445
        full_args = dict(
446
                cidr='192.168.0.0/24',
447
                gateway='192.168.0.1',
448
                type='MAC_FILTERED',
449
                dhcp=True)
450
        test_args = dict(full_args)
451
        test_args.update(dict(empty=None, full=None))
452
        for arg, val in test_args.items():
453
            kwargs = {} if arg == 'empty' else full_args if (
454
                arg == 'full') else {arg: val}
455
            r = self.client.create_network(net_name, **kwargs)
456
            self.assertEqual(self.client.http_client.url, self.url)
457
            self.assertEqual(
458
                self.client.http_client.path,
459
                '/networks')
460
            self.assert_dicts_are_equal(r, net_recv['network'])
461
            data = PR.call_args[0][1]
462
            expected = dict(network=dict(net_send['network']))
463
            expected['network'].update(kwargs)
464
            self.assert_dicts_are_equal(loads(data), expected)
465

466
    @patch('%s.perform_request' % khttp, return_value=FR())
467
    def test_connect_server(self, PR):
468
        vm_id = vm_recv['server']['id']
469
        net_id = net_recv['network']['id']
470
        FR.status_code = 202
471
        self.client.connect_server(vm_id, net_id)
472
        self.assertEqual(self.client.http_client.url, self.url)
473
        self.assertEqual(
474
            self.client.http_client.path,
475
            '/networks/%s/action' % net_id)
476
        self.assertEqual(
477
            PR.call_args[0],
478
            ('post', '{"add": {"serverRef": %s}}' % vm_id, {}, {}))
479

480
    @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
481
    def test_disconnect_server(self, NP):
482
        vm_id = vm_recv['server']['id']
483
        net_id = net_recv['network']['id']
484
        nic_id = 'nic-%s-%s' % (net_id, vm_id)
485
        vm_nics = [
486
            dict(id=nic_id, network_id=net_id),
487
            dict(id='another-nic-id', network_id='another-net-id'),
488
            dict(id=nic_id * 2, network_id=net_id * 2)]
489
        with patch.object(
490
                CycladesClient,
491
                'list_server_nics',
492
                return_value=vm_nics) as LSN:
493
            r = self.client.disconnect_server(vm_id, nic_id)
494
            self.assertEqual(r, 1)
495
            self.assertEqual(LSN.call_args[0], (vm_id,))
496
            self.assertEqual(NP.call_args[0], (net_id, 'action'))
497
            self.assertEqual(
498
                NP.call_args[1],
499
                dict(json_data=dict(remove=dict(attachment=nic_id))))
500

501
    @patch('%s.perform_request' % khttp, return_value=FR())
502
    def test_list_server_nics(self, PR):
503
        vm_id = vm_recv['server']['id']
504
        nics = dict(addresses=dict(values=[dict(id='nic1'), dict(id='nic2')]))
505
        FR.json = nics
506
        r = self.client.list_server_nics(vm_id)
507
        self.assertEqual(self.client.http_client.url, self.url)
508
        self.assertEqual(
509
            self.client.http_client.path,
510
            '/servers/%s/ips' % vm_id)
511
        expected = nics['addresses']['values']
512
        for i in range(len(r)):
513
            self.assert_dicts_are_equal(r[i], expected[i])
514

515
    @patch('%s.perform_request' % khttp, return_value=FR())
516
    def test_list_networks(self, PR):
517
        FR.json = net_list
518
        r = self.client.list_networks()
519
        self.assertEqual(self.client.http_client.url, self.url)
520
        self.assertEqual(self.client.http_client.path, '/networks')
521
        expected = net_list['networks']['values']
522
        for i in range(len(r)):
523
            self.assert_dicts_are_equal(expected[i], r[i])
524
        self.client.list_networks(detail=True)
525
        self.assertEqual(self.client.http_client.url, self.url)
526
        self.assertEqual(self.client.http_client.path, '/networks/detail')
527

528
    @patch('%s.perform_request' % khttp, return_value=FR())
529
    def test_list_network_nics(self, PR):
530
        net_id = net_recv['network']['id']
531
        FR.json = net_recv
532
        r = self.client.list_network_nics(net_id)
533
        self.assertEqual(self.client.http_client.url, self.url)
534
        self.assertEqual(
535
            self.client.http_client.path,
536
            '/networks/%s' % net_id)
537
        expected = net_recv['network']['attachments']['values']
538
        for i in range(len(r)):
539
            self.assert_dicts_are_equal(r[i], expected[i])
540

541
    @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
542
    def test_disconnect_network_nics(self, NP):
543
        net_id = net_recv['network']['id']
544
        nics = ['nic1', 'nic2', 'nic3']
545
        with patch.object(
546
                CycladesClient,
547
                'list_network_nics',
548
                return_value=nics) as lnn:
549
            self.client.disconnect_network_nics(net_id)
550
            lnn.assert_called_once_with(net_id)
551
            for i in range(len(nics)):
552
                expected = call(net_id, 'action', json_data=dict(
553
                    remove=dict(attachment=nics[i])))
554
                self.assertEqual(expected, NP.mock_calls[i])
555

556
    @patch('%s.perform_request' % khttp, return_value=FR())
557
    def test_get_network_details(self, PR):
558
        FR.json = net_recv
559
        net_id = net_recv['network']['id']
560
        r = self.client.get_network_details(net_id)
561
        self.assertEqual(self.client.http_client.url, self.url)
562
        self.assertEqual(
563
            self.client.http_client.path,
564
            '/networks/%s' % net_id)
565
        self.assert_dicts_are_equal(r, net_recv['network'])
566

567
    @patch('%s.perform_request' % khttp, return_value=FR())
568
    def test_update_network_name(self, PR):
569
        net_id = net_recv['network']['id']
570
        new_name = '%s_new' % net_id
571
        FR.status_code = 204
572
        self.client.update_network_name(net_id, new_name)
573
        self.assertEqual(self.client.http_client.url, self.url)
574
        self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
575
        (method, data, a_headers, a_params) = PR.call_args[0]
576
        self.assert_dicts_are_equal(
577
            dict(network=dict(name=new_name)),
578
            loads(data))
579

580
    @patch('%s.perform_request' % khttp, return_value=FR())
581
    def test_delete_server(self, PR):
582
        vm_id = vm_recv['server']['id']
583
        FR.status_code = 204
584
        self.client.delete_server(vm_id)
585
        self.assertEqual(self.client.http_client.url, self.url)
586
        self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
587

588
    @patch('%s.perform_request' % khttp, return_value=FR())
589
    def test_delete_image(self, PR):
590
        FR.status_code = 204
591
        self.client.delete_image(img_ref)
592
        self.assertEqual(self.client.http_client.url, self.url)
593
        self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
594

595
    @patch('%s.perform_request' % khttp, return_value=FR())
596
    def test_delete_network(self, PR):
597
        net_id = net_recv['network']['id']
598
        FR.status_code = 204
599
        self.client.delete_network(net_id)
600
        self.assertEqual(self.client.http_client.url, self.url)
601
        self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
602

603
    @patch('%s.perform_request' % khttp, return_value=FR())
604
    def test_create_image_metadata(self, PR):
605
        metadata = dict(m1='v1', m2='v2', m3='v3')
606
        FR.json = dict(meta=img_recv['image'])
607
        self.assertRaises(
608
            ClientError,
609
            self.client.create_image_metadata,
610
            img_ref, 'key', 'value')
611
        FR.status_code = 201
612
        for k, v in metadata.items():
613
            r = self.client.create_image_metadata(img_ref, k, v)
614
            self.assertEqual(self.client.http_client.url, self.url)
615
            self.assertEqual(
616
                self.client.http_client.path,
617
                '/images/%s/meta/%s' % (img_ref, k))
618
            (method, data, a_headers, a_params) = PR.call_args[0]
619
            self.assertEqual(dict(meta={k: v}), loads(data))
620
            self.assert_dicts_are_equal(r, img_recv['image'])
621

622
    @patch('%s.images_post' % cyclades_pkg, return_value=FR())
623
    def test_update_image_metadata(self, images_post):
624
        metadata = dict(m1='v1', m2='v2', m3='v3')
625
        FR.json = dict(metadata=metadata)
626
        r = self.client.update_image_metadata(img_ref, **metadata)
627
        self.assert_dicts_are_equal(r, metadata)
628
        (called_id, cmd) = images_post.call_args[0]
629
        self.assertEqual(called_id, img_ref)
630
        self.assertEqual(cmd, 'meta')
631
        data = images_post.call_args[1]['json_data']
632
        self.assert_dicts_are_equal(data, dict(metadata=metadata))
633

634
    @patch('%s.images_delete' % cyclades_pkg, return_value=FR())
635
    def test_delete_image_metadata(self, images_delete):
636
        key = 'metakey'
637
        self.client.delete_image_metadata(img_ref, key)
638
        self.assertEqual(
639
            (img_ref, '/meta/' + key),
640
            images_delete.call_args[0])
641
    """
642

    
643
if __name__ == '__main__':
644
    from sys import argv
645
    from kamaki.clients.test import runTestCase
646
    runTestCase(Cyclades, 'Cyclades (multi) Client', argv[1:])