Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / test.py @ 2ace03e5

History | View | Annotate | Download (25.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

    
43
khttp_pkg = 'kamaki.clients.connection.kamakicon.KamakiHTTPConnection'
44
compute_pkg = 'kamaki.clients.cyclades.CycladesClient'
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(values=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(values=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=dict(values=[
85
    dict(name='n1', id=1),
86
    dict(name='n2', id=2)]))
87
flavor_list = dict(flavors=dict(values=[
88
        dict(id=41, name="C1R1024D20"),
89
        dict(id=42, name="C1R1024D40"),
90
        dict(id=43, name="C1R1028D20")]))
91
img_list = dict(images=dict(values=[
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
net_send = dict(network=dict(dhcp=False, name='someNet'))
101
net_recv = dict(network=dict(
102
    status="PENDING",
103
    updated="2013-03-05T15:04:51.758780+00:00",
104
    name="someNet",
105
    created="2013-03-05T15:04:51.758728+00:00",
106
    cidr6=None,
107
    id="2130",
108
    gateway6=None,
109
    public=False,
110
    dhcp=False,
111
    cidr="192.168.1.0/24",
112
    type="MAC_FILTERED",
113
    gateway=None,
114
    attachments=dict(values=[dict(name='att1'), dict(name='att2')])))
115
net_list = dict(networks=dict(values=[
116
    dict(id=1, name='n1'),
117
    dict(id=2, name='n2'),
118
    dict(id=3, name='n3')]))
119

    
120

    
121
class FR(object):
122
    """FR stands for Fake Response"""
123
    json = vm_recv
124
    headers = {}
125
    content = json
126
    status = None
127
    status_code = 200
128

    
129
    def release(self):
130
        pass
131

    
132

    
133
class Cyclades(TestCase):
134

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

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

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

    
155
    @patch(
156
        '%s.get_image_details' % compute_pkg,
157
        return_value=img_recv['image'])
158
    def test_create_server(self, GID):
159
        with patch.object(
160
                CycladesClient, 'servers_post',
161
                side_effect=ClientError(
162
                    'REQUEST ENTITY TOO LARGE',
163
                    status=403)):
164
            self.assertRaises(
165
                ClientError,
166
                self.client.create_server,
167
                vm_name, fid, img_ref)
168
        self.assertEqual(GID.mock_calls[-1], call(img_ref))
169

    
170
        with patch.object(
171
                CycladesClient, 'servers_post',
172
                return_value=FR()) as post:
173
            r = self.client.create_server(vm_name, fid, img_ref)
174
            self.assertEqual(r, FR.json['server'])
175
            self.assertEqual(GID.mock_calls[-1], call(img_ref))
176
            self.assertEqual(post.mock_calls[-1], call(json_data=vm_send))
177
            prsn = 'Personality string (does not work with real servers)'
178
            self.client.create_server(vm_name, fid, img_ref, prsn)
179
            expected = dict(server=dict(vm_send['server']))
180
            expected['server']['personality'] = prsn
181
            self.assertEqual(post.mock_calls[-1], call(json_data=expected))
182

    
183
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
184
    def test_list_servers(self, SG):
185
        FR.json = vm_list
186
        for detail in (False, True):
187
            r = self.client.list_servers(detail)
188
            for i, vm in enumerate(vm_list['servers']['values']):
189
                self.assert_dicts_are_equal(r[i], vm)
190
            self.assertEqual(i + 1, len(r))
191
            self.assertEqual(SG.mock_calls[-1], call(
192
                changes_since=None,
193
                command='detail' if detail else ''))
194

    
195
    @patch('%s.servers_get' % compute_pkg, return_value=FR())
196
    def test_get_server_details(self, SG):
197
        vm_id = vm_recv['server']['id']
198
        r = self.client.get_server_details(vm_id)
199
        self.assert_dicts_are_equal(r, vm_recv['server'])
200
        self.assertEqual(SG.mock_calls[-1], call(vm_id))
201

    
202
    @patch('%s.servers_put' % compute_pkg, return_value=FR())
203
    def test_update_server_name(self, SP):
204
        vm_id = vm_recv['server']['id']
205
        new_name = vm_name + '_new'
206
        self.client.update_server_name(vm_id, new_name)
207
        self.assertEqual(SP.mock_calls[-1], call(vm_id, json_data=dict(
208
            server=dict(name=new_name))))
209

    
210
    """
211
    @patch('%s.perform_request' % khttp, return_value=FR())
212
    def test_reboot_server(self, PR):
213
        vm_id = vm_recv['server']['id']
214
        FR.status_code = 202
215
        self.client.reboot_server(vm_id)
216
        self.assertEqual(self.client.http_client.url, self.url)
217
        self.assertEqual(
218
            self.client.http_client.path,
219
            '/servers/%s/action' % vm_id)
220
        (method, data, a_headers, a_params) = PR.call_args[0]
221
        self.assert_dicts_are_equal(
222
            dict(reboot=dict(type='SOFT')),
223
            loads(data))
224

225
    @patch('%s.perform_request' % khttp, return_value=FR())
226
    def test_create_server_metadata(self, PR):
227
        vm_id = vm_recv['server']['id']
228
        metadata = dict(m1='v1', m2='v2', m3='v3')
229
        FR.json = dict(meta=vm_recv['server'])
230
        self.assertRaises(
231
            ClientError,
232
            self.client.create_server_metadata,
233
            vm_id, 'key', 'value')
234
        FR.status_code = 201
235
        for k, v in metadata.items():
236
            r = self.client.create_server_metadata(vm_id, k, v)
237
            self.assertEqual(self.client.http_client.url, self.url)
238
            self.assertEqual(
239
                self.client.http_client.path,
240
                '/servers/%s/meta/%s' % (vm_id, k))
241
            (method, data, a_headers, a_params) = PR.call_args[0]
242
            self.assertEqual(dict(meta={k: v}), loads(data))
243
            self.assert_dicts_are_equal(r, vm_recv['server'])
244

245
    @patch('%s.perform_request' % khttp, return_value=FR())
246
    def test_get_server_metadata(self, PR):
247
        vm_id = vm_recv['server']['id']
248
        metadata = dict(m1='v1', m2='v2', m3='v3')
249
        FR.json = dict(metadata=dict(values=metadata))
250
        r = self.client.get_server_metadata(vm_id)
251
        self.assertEqual(self.client.http_client.url, self.url)
252
        self.assertEqual(
253
            self.client.http_client.path,
254
            '/servers/%s/meta' % vm_id)
255
        self.assert_dicts_are_equal(r, metadata)
256

257
        for k, v in metadata.items():
258
            FR.json = dict(meta={k: v})
259
            r = self.client.get_server_metadata(vm_id, k)
260
            self.assertEqual(self.client.http_client.url, self.url)
261
            self.assertEqual(
262
                self.client.http_client.path,
263
                '/servers/%s/meta/%s' % (vm_id, k))
264
            self.assert_dicts_are_equal(r, {k: v})
265

266
    @patch('%s.servers_post' % cyclades_pkg, return_value=FR())
267
    def test_update_server_metadata(self, servers_post):
268
        vm_id = vm_recv['server']['id']
269
        metadata = dict(m1='v1', m2='v2', m3='v3')
270
        FR.json = dict(metadata=metadata)
271
        r = self.client.update_server_metadata(vm_id, **metadata)
272
        self.assert_dicts_are_equal(r, metadata)
273
        (called_id, cmd) = servers_post.call_args[0]
274
        self.assertEqual(called_id, vm_id)
275
        self.assertEqual(cmd, 'meta')
276
        data = servers_post.call_args[1]['json_data']
277
        self.assert_dicts_are_equal(data, dict(metadata=metadata))
278

279
    @patch('%s.servers_delete' % cyclades_pkg, return_value=FR())
280
    def test_delete_server_metadata(self, servers_delete):
281
        vm_id = vm_recv['server']['id']
282
        key = 'metakey'
283
        self.client.delete_server_metadata(vm_id, key)
284
        self.assertEqual((vm_id, 'meta/' + key), servers_delete.call_args[0])
285

286
    @patch('%s.perform_request' % khttp, return_value=FR())
287
    def test_list_flavors(self, PR):
288
        FR.json = flavor_list
289
        r = self.client.list_flavors()
290
        self.assertEqual(self.client.http_client.url, self.url)
291
        self.assertEqual(self.client.http_client.path, '/flavors')
292
        (method, data, a_headers, a_params) = PR.call_args[0]
293
        self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
294
        r = self.client.list_flavors(detail=True)
295
        self.assertEqual(self.client.http_client.url, self.url)
296
        self.assertEqual(self.client.http_client.path, '/flavors/detail')
297

298
    @patch('%s.perform_request' % khttp, return_value=FR())
299
    def test_get_flavor_details(self, PR):
300
        FR.json = dict(flavor=flavor_list['flavors'])
301
        r = self.client.get_flavor_details(fid)
302
        self.assertEqual(self.client.http_client.url, self.url)
303
        self.assertEqual(self.client.http_client.path, '/flavors/%s' % fid)
304
        self.assert_dicts_are_equal(r, flavor_list['flavors'])
305

306
    @patch('%s.perform_request' % khttp, return_value=FR())
307
    def test_list_images(self, PR):
308
        FR.json = img_list
309
        r = self.client.list_images()
310
        self.assertEqual(self.client.http_client.url, self.url)
311
        self.assertEqual(self.client.http_client.path, '/images')
312
        expected = img_list['images']['values']
313
        for i in range(len(r)):
314
            self.assert_dicts_are_equal(expected[i], r[i])
315
        self.client.list_images(detail=True)
316
        self.assertEqual(self.client.http_client.url, self.url)
317
        self.assertEqual(self.client.http_client.path, '/images/detail')
318

319
    @patch('%s.perform_request' % khttp, return_value=FR())
320
    def test_get_image_details(self, PR):
321
        FR.json = img_recv
322
        r = self.client.get_image_details(img_ref)
323
        self.assertEqual(self.client.http_client.url, self.url)
324
        self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
325
        self.assert_dicts_are_equal(r, img_recv['image'])
326

327
    @patch('%s.images_get' % cyclades_pkg, return_value=FR())
328
    def test_get_image_metadata(self, IG):
329
        FR.json = dict(metadata=dict(values=img_recv['image']))
330
        r = self.client.get_image_metadata(img_ref)
331
        self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta'))
332
        self.assert_dicts_are_equal(img_recv['image'], r)
333
        FR.json = dict(meta=img_recv['image'])
334
        key = 'somekey'
335
        self.client.get_image_metadata(img_ref, key)
336
        self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta/%s' % key))
337

338
    @patch('%s.perform_request' % khttp, return_value=FR())
339
    def test_shutdown_server(self, PR):
340
        vm_id = vm_recv['server']['id']
341
        FR.status_code = 202
342
        self.client.shutdown_server(vm_id)
343
        self.assertEqual(self.client.http_client.url, self.url)
344
        self.assertEqual(
345
            self.client.http_client.path,
346
            '/servers/%s/action' % vm_id)
347
        self.assertEqual(
348
            PR.call_args[0],
349
            ('post',  '{"shutdown": {}}', {}, {}))
350

351
    @patch('%s.perform_request' % khttp, return_value=FR())
352
    def test_start_server(self, PR):
353
        vm_id = vm_recv['server']['id']
354
        FR.status_code = 202
355
        self.client.start_server(vm_id)
356
        self.assertEqual(self.client.http_client.url, self.url)
357
        self.assertEqual(
358
            self.client.http_client.path,
359
            '/servers/%s/action' % vm_id)
360
        self.assertEqual(PR.call_args[0], ('post',  '{"start": {}}', {}, {}))
361

362
    @patch('%s.perform_request' % khttp, return_value=FR())
363
    def test_get_server_console(self, PR):
364
        cnsl = dict(console=dict(info1='i1', info2='i2', info3='i3'))
365
        FR.json = cnsl
366
        vm_id = vm_recv['server']['id']
367
        r = self.client.get_server_console(vm_id)
368
        self.assertEqual(self.client.http_client.url, self.url)
369
        self.assertEqual(
370
            self.client.http_client.path,
371
            '/servers/%s/action' % vm_id)
372
        self.assert_dicts_are_equal(cnsl['console'], r)
373
        self.assertEqual(
374
            PR.call_args[0],
375
            ('post',  '{"console": {"type": "vnc"}}', {}, {}))
376

377
    def test_get_firewall_profile(self):
378
        vm_id = vm_recv['server']['id']
379
        v = 'Some profile'
380
        ret = {'attachments': {'values': [{'firewallProfile': v, 1:1}]}}
381
        with patch.object(
382
                CycladesClient,
383
                'get_server_details',
384
                return_value=ret) as GSD:
385
            r = self.client.get_firewall_profile(vm_id)
386
            self.assertEqual(r, v)
387
            self.assertEqual(GSD.call_args[0], (vm_id,))
388
            ret['attachments']['values'][0].pop('firewallProfile')
389
            self.assertRaises(
390
                ClientError,
391
                self.client.get_firewall_profile,
392
                vm_id)
393

394
    @patch('%s.perform_request' % khttp, return_value=FR())
395
    def test_set_firewall_profile(self, PR):
396
        vm_id = vm_recv['server']['id']
397
        v = 'Some profile'
398
        FR.status_code = 202
399
        self.client.set_firewall_profile(vm_id, v)
400
        self.assertEqual(self.client.http_client.url, self.url)
401
        self.assertEqual(
402
            self.client.http_client.path,
403
            '/servers/%s/action' % vm_id)
404
        self.assertEqual(PR.call_args[0], (
405
            'post',
406
            '{"firewallProfile": {"profile": "%s"}}' % v,
407
            {},
408
            {}))
409

410
    @patch('%s.perform_request' % khttp, return_value=FR())
411
    def test_get_server_stats(self, PR):
412
        vm_id = vm_recv['server']['id']
413
        stats = dict(stat1='v1', stat2='v2', stat3='v3', stat4='v4')
414
        FR.json = dict(stats=stats)
415
        r = self.client.get_server_stats(vm_id)
416
        self.assertEqual(self.client.http_client.url, self.url)
417
        self.assertEqual(
418
            self.client.http_client.path,
419
            '/servers/%s/stats' % vm_id)
420
        self.assert_dicts_are_equal(stats, r)
421

422
    @patch('%s.perform_request' % khttp, return_value=FR())
423
    def test_create_network(self, PR):
424
        net_name = net_send['network']['name']
425
        FR.json = net_recv
426
        FR.status_code = 202
427
        full_args = dict(
428
                cidr='192.168.0.0/24',
429
                gateway='192.168.0.1',
430
                type='MAC_FILTERED',
431
                dhcp=True)
432
        test_args = dict(full_args)
433
        test_args.update(dict(empty=None, full=None))
434
        for arg, val in test_args.items():
435
            kwargs = {} if arg == 'empty' else full_args if (
436
                arg == 'full') else {arg: val}
437
            r = self.client.create_network(net_name, **kwargs)
438
            self.assertEqual(self.client.http_client.url, self.url)
439
            self.assertEqual(
440
                self.client.http_client.path,
441
                '/networks')
442
            self.assert_dicts_are_equal(r, net_recv['network'])
443
            data = PR.call_args[0][1]
444
            expected = dict(network=dict(net_send['network']))
445
            expected['network'].update(kwargs)
446
            self.assert_dicts_are_equal(loads(data), expected)
447

448
    @patch('%s.perform_request' % khttp, return_value=FR())
449
    def test_connect_server(self, PR):
450
        vm_id = vm_recv['server']['id']
451
        net_id = net_recv['network']['id']
452
        FR.status_code = 202
453
        self.client.connect_server(vm_id, net_id)
454
        self.assertEqual(self.client.http_client.url, self.url)
455
        self.assertEqual(
456
            self.client.http_client.path,
457
            '/networks/%s/action' % net_id)
458
        self.assertEqual(
459
            PR.call_args[0],
460
            ('post', '{"add": {"serverRef": %s}}' % vm_id, {}, {}))
461

462
    @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
463
    def test_disconnect_server(self, NP):
464
        vm_id = vm_recv['server']['id']
465
        net_id = net_recv['network']['id']
466
        nic_id = 'nic-%s-%s' % (net_id, vm_id)
467
        vm_nics = [
468
            dict(id=nic_id, network_id=net_id),
469
            dict(id='another-nic-id', network_id='another-net-id'),
470
            dict(id=nic_id * 2, network_id=net_id * 2)]
471
        with patch.object(
472
                CycladesClient,
473
                'list_server_nics',
474
                return_value=vm_nics) as LSN:
475
            r = self.client.disconnect_server(vm_id, nic_id)
476
            self.assertEqual(r, 1)
477
            self.assertEqual(LSN.call_args[0], (vm_id,))
478
            self.assertEqual(NP.call_args[0], (net_id, 'action'))
479
            self.assertEqual(
480
                NP.call_args[1],
481
                dict(json_data=dict(remove=dict(attachment=nic_id))))
482

483
    @patch('%s.perform_request' % khttp, return_value=FR())
484
    def test_list_server_nics(self, PR):
485
        vm_id = vm_recv['server']['id']
486
        nics = dict(addresses=dict(values=[dict(id='nic1'), dict(id='nic2')]))
487
        FR.json = nics
488
        r = self.client.list_server_nics(vm_id)
489
        self.assertEqual(self.client.http_client.url, self.url)
490
        self.assertEqual(
491
            self.client.http_client.path,
492
            '/servers/%s/ips' % vm_id)
493
        expected = nics['addresses']['values']
494
        for i in range(len(r)):
495
            self.assert_dicts_are_equal(r[i], expected[i])
496

497
    @patch('%s.perform_request' % khttp, return_value=FR())
498
    def test_list_networks(self, PR):
499
        FR.json = net_list
500
        r = self.client.list_networks()
501
        self.assertEqual(self.client.http_client.url, self.url)
502
        self.assertEqual(self.client.http_client.path, '/networks')
503
        expected = net_list['networks']['values']
504
        for i in range(len(r)):
505
            self.assert_dicts_are_equal(expected[i], r[i])
506
        self.client.list_networks(detail=True)
507
        self.assertEqual(self.client.http_client.url, self.url)
508
        self.assertEqual(self.client.http_client.path, '/networks/detail')
509

510
    @patch('%s.perform_request' % khttp, return_value=FR())
511
    def test_list_network_nics(self, PR):
512
        net_id = net_recv['network']['id']
513
        FR.json = net_recv
514
        r = self.client.list_network_nics(net_id)
515
        self.assertEqual(self.client.http_client.url, self.url)
516
        self.assertEqual(
517
            self.client.http_client.path,
518
            '/networks/%s' % net_id)
519
        expected = net_recv['network']['attachments']['values']
520
        for i in range(len(r)):
521
            self.assert_dicts_are_equal(r[i], expected[i])
522

523
    @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
524
    def test_disconnect_network_nics(self, NP):
525
        net_id = net_recv['network']['id']
526
        nics = ['nic1', 'nic2', 'nic3']
527
        with patch.object(
528
                CycladesClient,
529
                'list_network_nics',
530
                return_value=nics) as lnn:
531
            self.client.disconnect_network_nics(net_id)
532
            lnn.assert_called_once_with(net_id)
533
            for i in range(len(nics)):
534
                expected = call(net_id, 'action', json_data=dict(
535
                    remove=dict(attachment=nics[i])))
536
                self.assertEqual(expected, NP.mock_calls[i])
537

538
    @patch('%s.perform_request' % khttp, return_value=FR())
539
    def test_get_network_details(self, PR):
540
        FR.json = net_recv
541
        net_id = net_recv['network']['id']
542
        r = self.client.get_network_details(net_id)
543
        self.assertEqual(self.client.http_client.url, self.url)
544
        self.assertEqual(
545
            self.client.http_client.path,
546
            '/networks/%s' % net_id)
547
        self.assert_dicts_are_equal(r, net_recv['network'])
548

549
    @patch('%s.perform_request' % khttp, return_value=FR())
550
    def test_update_network_name(self, PR):
551
        net_id = net_recv['network']['id']
552
        new_name = '%s_new' % net_id
553
        FR.status_code = 204
554
        self.client.update_network_name(net_id, new_name)
555
        self.assertEqual(self.client.http_client.url, self.url)
556
        self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
557
        (method, data, a_headers, a_params) = PR.call_args[0]
558
        self.assert_dicts_are_equal(
559
            dict(network=dict(name=new_name)),
560
            loads(data))
561

562
    @patch('%s.perform_request' % khttp, return_value=FR())
563
    def test_delete_server(self, PR):
564
        vm_id = vm_recv['server']['id']
565
        FR.status_code = 204
566
        self.client.delete_server(vm_id)
567
        self.assertEqual(self.client.http_client.url, self.url)
568
        self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
569

570
    @patch('%s.perform_request' % khttp, return_value=FR())
571
    def test_delete_image(self, PR):
572
        FR.status_code = 204
573
        self.client.delete_image(img_ref)
574
        self.assertEqual(self.client.http_client.url, self.url)
575
        self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
576

577
    @patch('%s.perform_request' % khttp, return_value=FR())
578
    def test_delete_network(self, PR):
579
        net_id = net_recv['network']['id']
580
        FR.status_code = 204
581
        self.client.delete_network(net_id)
582
        self.assertEqual(self.client.http_client.url, self.url)
583
        self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
584

585
    @patch('%s.perform_request' % khttp, return_value=FR())
586
    def test_create_image_metadata(self, PR):
587
        metadata = dict(m1='v1', m2='v2', m3='v3')
588
        FR.json = dict(meta=img_recv['image'])
589
        self.assertRaises(
590
            ClientError,
591
            self.client.create_image_metadata,
592
            img_ref, 'key', 'value')
593
        FR.status_code = 201
594
        for k, v in metadata.items():
595
            r = self.client.create_image_metadata(img_ref, k, v)
596
            self.assertEqual(self.client.http_client.url, self.url)
597
            self.assertEqual(
598
                self.client.http_client.path,
599
                '/images/%s/meta/%s' % (img_ref, k))
600
            (method, data, a_headers, a_params) = PR.call_args[0]
601
            self.assertEqual(dict(meta={k: v}), loads(data))
602
            self.assert_dicts_are_equal(r, img_recv['image'])
603

604
    @patch('%s.images_post' % cyclades_pkg, return_value=FR())
605
    def test_update_image_metadata(self, images_post):
606
        metadata = dict(m1='v1', m2='v2', m3='v3')
607
        FR.json = dict(metadata=metadata)
608
        r = self.client.update_image_metadata(img_ref, **metadata)
609
        self.assert_dicts_are_equal(r, metadata)
610
        (called_id, cmd) = images_post.call_args[0]
611
        self.assertEqual(called_id, img_ref)
612
        self.assertEqual(cmd, 'meta')
613
        data = images_post.call_args[1]['json_data']
614
        self.assert_dicts_are_equal(data, dict(metadata=metadata))
615

616
    @patch('%s.images_delete' % cyclades_pkg, return_value=FR())
617
    def test_delete_image_metadata(self, images_delete):
618
        key = 'metakey'
619
        self.client.delete_image_metadata(img_ref, key)
620
        self.assertEqual(
621
            (img_ref, '/meta/' + key),
622
            images_delete.call_args[0])
623
    """
624

    
625
if __name__ == '__main__':
626
    from sys import argv
627
    from kamaki.clients.test import runTestCase
628
    runTestCase(Cyclades, 'Cyclades (multi) Client', argv[1:])