Rearange client packages 4 uniformity in testing
[kamaki] / kamaki / clients / cyclades / test.py
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 from mock import patch, Mock, call
34 from unittest import TestCase
35 from json import loads
36
37 from kamaki.clients import Client, ClientError
38 from kamaki.clients.cyclades import CycladesClient
39 from kamaki.clients.cyclades_rest_api import CycladesClientApi
40
41 img_ref = "1m4g3-r3f3r3nc3"
42 vm_name = "my new VM"
43 fid = 42
44 vm_send = dict(server=dict(
45     flavorRef=fid,
46     name=vm_name,
47     imageRef=img_ref,
48     metadata=dict(os="debian", users="root")))
49 vm_recv = dict(server=dict(
50     status="BUILD",
51     updated="2013-03-01T10:04:00.637152+00:00",
52     hostId="",
53     name=vm_name,
54     imageRef=img_ref,
55     created="2013-03-01T10:04:00.087324+00:00",
56     flavorRef=fid,
57     adminPass="n0n3sh@11p@55",
58     suspended=False,
59     progress=0,
60     id=31173,
61     metadata=dict(values=dict(os="debian", users="root"))))
62 img_recv = dict(image=dict(
63     status="ACTIVE",
64     updated="2013-02-26T11:10:14+00:00",
65     name="Debian Base",
66     created="2013-02-26T11:03:29+00:00",
67     progress=100,
68     id=img_ref,
69     metadata=dict(values=dict(
70         partition_table="msdos",
71         kernel="2.6.32",
72         osfamily="linux",
73         users="root",
74         gui="No GUI",
75         sortorder="1",
76         os="debian",
77         root_partition="1",
78         description="Debian 6.0.7 (Squeeze) Base System"))))
79 vm_list = dict(servers=dict(values=[
80     dict(name='n1', id=1),
81     dict(name='n2', id=2)]))
82 flavor_list = dict(flavors=dict(values=[
83         dict(id=41, name="C1R1024D20"),
84         dict(id=42, name="C1R1024D40"),
85         dict(id=43, name="C1R1028D20")]))
86 img_list = dict(images=dict(values=[
87     dict(name="maelstrom", id="0fb03e45-7d5a-4515-bd4e-e6bbf6457f06"),
88     dict(name="edx_saas", id="1357163d-5fd8-488e-a117-48734c526206"),
89     dict(name="Debian_Wheezy_Base", id="1f8454f0-8e3e-4b6c-ab8e-5236b728dffe"),
90     dict(name="CentOS", id="21894b48-c805-4568-ac8b-7d4bb8eb533d"),
91     dict(name="Ubuntu Desktop", id="37bc522c-c479-4085-bfb9-464f9b9e2e31"),
92     dict(name="Ubuntu 12.10", id="3a24fef9-1a8c-47d1-8f11-e07bd5e544fd"),
93     dict(name="Debian Base", id="40ace203-6254-4e17-a5cb-518d55418a7d"),
94     dict(name="ubuntu_bundled", id="5336e265-5c7c-4127-95cb-2bf832a79903")]))
95 net_send = dict(network=dict(dhcp=False, name='someNet'))
96 net_recv = dict(network=dict(
97     status="PENDING",
98     updated="2013-03-05T15:04:51.758780+00:00",
99     name="someNet",
100     created="2013-03-05T15:04:51.758728+00:00",
101     cidr6=None,
102     id="2130",
103     gateway6=None,
104     public=False,
105     dhcp=False,
106     cidr="192.168.1.0/24",
107     type="MAC_FILTERED",
108     gateway=None,
109     attachments=dict(values=[dict(name='att1'), dict(name='att2')])))
110 net_list = dict(networks=dict(values=[
111     dict(id=1, name='n1'),
112     dict(id=2, name='n2'),
113     dict(id=3, name='n3')]))
114
115
116 class FR(object):
117     """FR stands for Fake Response"""
118     json = vm_recv
119     headers = {}
120     content = json
121     status = None
122     status_code = 200
123
124     def release(self):
125         pass
126
127 khttp = 'kamaki.clients.connection.kamakicon.KamakiHTTPConnection'
128 cyclades_pkg = 'kamaki.clients.cyclades.CycladesClient'
129
130
131 class Cyclades(TestCase):
132
133     def assert_dicts_are_equal(self, d1, d2):
134         for k, v in d1.items():
135             self.assertTrue(k in d2)
136             if isinstance(v, dict):
137                 self.assert_dicts_are_equal(v, d2[k])
138             else:
139                 self.assertEqual(unicode(v), unicode(d2[k]))
140
141     """Set up a Cyclades thorough test"""
142     def setUp(self):
143         self.url = 'http://cyclades.example.com'
144         self.token = 'cyc14d3s70k3n'
145         self.client = CycladesClient(self.url, self.token)
146         from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
147         self.C = KamakiHTTPConnection
148
149     def tearDown(self):
150         FR.status_code = 200
151         FR.json = vm_recv
152
153     def test_create_server(self):
154         self.client.get_image_details = Mock(return_value=img_recv['image'])
155         with patch.object(Client, 'request', side_effect=ClientError(
156                 'REQUEST ENTITY TOO LARGE',
157                 status=403)):
158             self.assertRaises(
159                 ClientError,
160                 self.client.create_server,
161                 vm_name, fid, img_ref)
162
163         with patch.object(
164                 self.C,
165                 'perform_request',
166                 return_value=FR()) as perform_req:
167             self.assertRaises(
168                 ClientError,
169                 self.client.create_server,
170                 vm_name, fid, img_ref)
171             FR.status_code = 202
172             r = self.client.create_server(vm_name, fid, img_ref)
173             self.assertEqual(self.client.http_client.url, self.url)
174             self.assertEqual(self.client.http_client.path, '/servers')
175             (method, data, a_headers, a_params) = perform_req.call_args[0]
176             self.assert_dicts_are_equal(loads(data), vm_send)
177             self.assert_dicts_are_equal(r, vm_recv['server'])
178             prsn = 'Personality string (does not work with real servers)'
179             self.client.create_server(vm_name, fid, img_ref, prsn)
180             (method, data, a_headers, a_params) = perform_req.call_args[0]
181             data = loads(data)
182             self.assertTrue('personality' in data['server'])
183             self.assertEqual(prsn, data['server']['personality'])
184
185     def test_list_servers(self):
186         FR.json = vm_list
187         with patch.object(
188                 self.C,
189                 'perform_request',
190                 return_value=FR()) as perform_req:
191             r = self.client.list_servers()
192             self.assertEqual(self.client.http_client.url, self.url)
193             self.assertEqual(self.client.http_client.path, '/servers')
194             (method, data, a_headers, a_params) = perform_req.call_args[0]
195             self.assert_dicts_are_equal(dict(values=r), vm_list['servers'])
196             r = self.client.list_servers(detail=True)
197             self.assertEqual(self.client.http_client.url, self.url)
198             self.assertEqual(self.client.http_client.path, '/servers/detail')
199         with patch.object(
200                 CycladesClientApi,
201                 'servers_get',
202                 return_value=FR()) as servers_get:
203             self.client.list_servers(changes_since=True)
204             self.assertTrue(servers_get.call_args[1]['changes_since'])
205
206     @patch('%s.perform_request' % khttp, return_value=FR())
207     def test_get_server_details(self, PR):
208         vm_id = vm_recv['server']['id']
209         r = self.client.get_server_details(vm_id)
210         self.assertEqual(self.client.http_client.url, self.url)
211         self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
212         self.assert_dicts_are_equal(r, vm_recv['server'])
213
214     @patch('%s.perform_request' % khttp, return_value=FR())
215     def test_update_server_name(self, PR):
216         vm_id = vm_recv['server']['id']
217         new_name = vm_name + '_new'
218         FR.status_code = 204
219         self.client.update_server_name(vm_id, new_name)
220         self.assertEqual(self.client.http_client.url, self.url)
221         self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
222         (method, data, a_headers, a_params) = PR.call_args[0]
223         self.assert_dicts_are_equal(
224             dict(server=dict(name=new_name)),
225             loads(data))
226
227     @patch('%s.perform_request' % khttp, return_value=FR())
228     def test_reboot_server(self, PR):
229         vm_id = vm_recv['server']['id']
230         FR.status_code = 202
231         self.client.reboot_server(vm_id)
232         self.assertEqual(self.client.http_client.url, self.url)
233         self.assertEqual(
234             self.client.http_client.path,
235             '/servers/%s/action' % vm_id)
236         (method, data, a_headers, a_params) = PR.call_args[0]
237         self.assert_dicts_are_equal(
238             dict(reboot=dict(type='SOFT')),
239             loads(data))
240
241     @patch('%s.perform_request' % khttp, return_value=FR())
242     def test_create_server_metadata(self, PR):
243         vm_id = vm_recv['server']['id']
244         metadata = dict(m1='v1', m2='v2', m3='v3')
245         FR.json = dict(meta=vm_recv['server'])
246         self.assertRaises(
247             ClientError,
248             self.client.create_server_metadata,
249             vm_id, 'key', 'value')
250         FR.status_code = 201
251         for k, v in metadata.items():
252             r = self.client.create_server_metadata(vm_id, k, v)
253             self.assertEqual(self.client.http_client.url, self.url)
254             self.assertEqual(
255                 self.client.http_client.path,
256                 '/servers/%s/meta/%s' % (vm_id, k))
257             (method, data, a_headers, a_params) = PR.call_args[0]
258             self.assertEqual(dict(meta={k: v}), loads(data))
259             self.assert_dicts_are_equal(r, vm_recv['server'])
260
261     @patch('%s.perform_request' % khttp, return_value=FR())
262     def test_get_server_metadata(self, PR):
263         vm_id = vm_recv['server']['id']
264         metadata = dict(m1='v1', m2='v2', m3='v3')
265         FR.json = dict(metadata=dict(values=metadata))
266         r = self.client.get_server_metadata(vm_id)
267         self.assertEqual(self.client.http_client.url, self.url)
268         self.assertEqual(
269             self.client.http_client.path,
270             '/servers/%s/meta' % vm_id)
271         self.assert_dicts_are_equal(r, metadata)
272
273         for k, v in metadata.items():
274             FR.json = dict(meta={k: v})
275             r = self.client.get_server_metadata(vm_id, k)
276             self.assertEqual(self.client.http_client.url, self.url)
277             self.assertEqual(
278                 self.client.http_client.path,
279                 '/servers/%s/meta/%s' % (vm_id, k))
280             self.assert_dicts_are_equal(r, {k: v})
281
282     @patch('%s.servers_post' % cyclades_pkg, return_value=FR())
283     def test_update_server_metadata(self, servers_post):
284         vm_id = vm_recv['server']['id']
285         metadata = dict(m1='v1', m2='v2', m3='v3')
286         FR.json = dict(metadata=metadata)
287         r = self.client.update_server_metadata(vm_id, **metadata)
288         self.assert_dicts_are_equal(r, metadata)
289         (called_id, cmd) = servers_post.call_args[0]
290         self.assertEqual(called_id, vm_id)
291         self.assertEqual(cmd, 'meta')
292         data = servers_post.call_args[1]['json_data']
293         self.assert_dicts_are_equal(data, dict(metadata=metadata))
294
295     @patch('%s.servers_delete' % cyclades_pkg, return_value=FR())
296     def test_delete_server_metadata(self, servers_delete):
297         vm_id = vm_recv['server']['id']
298         key = 'metakey'
299         self.client.delete_server_metadata(vm_id, key)
300         self.assertEqual((vm_id, 'meta/' + key), servers_delete.call_args[0])
301
302     @patch('%s.perform_request' % khttp, return_value=FR())
303     def test_list_flavors(self, PR):
304         FR.json = flavor_list
305         r = self.client.list_flavors()
306         self.assertEqual(self.client.http_client.url, self.url)
307         self.assertEqual(self.client.http_client.path, '/flavors')
308         (method, data, a_headers, a_params) = PR.call_args[0]
309         self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
310         r = self.client.list_flavors(detail=True)
311         self.assertEqual(self.client.http_client.url, self.url)
312         self.assertEqual(self.client.http_client.path, '/flavors/detail')
313
314     @patch('%s.perform_request' % khttp, return_value=FR())
315     def test_get_flavor_details(self, PR):
316         FR.json = dict(flavor=flavor_list['flavors'])
317         r = self.client.get_flavor_details(fid)
318         self.assertEqual(self.client.http_client.url, self.url)
319         self.assertEqual(self.client.http_client.path, '/flavors/%s' % fid)
320         self.assert_dicts_are_equal(r, flavor_list['flavors'])
321
322     @patch('%s.perform_request' % khttp, return_value=FR())
323     def test_list_images(self, PR):
324         FR.json = img_list
325         r = self.client.list_images()
326         self.assertEqual(self.client.http_client.url, self.url)
327         self.assertEqual(self.client.http_client.path, '/images')
328         expected = img_list['images']['values']
329         for i in range(len(r)):
330             self.assert_dicts_are_equal(expected[i], r[i])
331         self.client.list_images(detail=True)
332         self.assertEqual(self.client.http_client.url, self.url)
333         self.assertEqual(self.client.http_client.path, '/images/detail')
334
335     @patch('%s.perform_request' % khttp, return_value=FR())
336     def test_get_image_details(self, PR):
337         FR.json = img_recv
338         r = self.client.get_image_details(img_ref)
339         self.assertEqual(self.client.http_client.url, self.url)
340         self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
341         self.assert_dicts_are_equal(r, img_recv['image'])
342
343     @patch('%s.images_get' % cyclades_pkg, return_value=FR())
344     def test_get_image_metadata(self, IG):
345         FR.json = dict(metadata=dict(values=img_recv['image']))
346         r = self.client.get_image_metadata(img_ref)
347         self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta'))
348         self.assert_dicts_are_equal(img_recv['image'], r)
349         FR.json = dict(meta=img_recv['image'])
350         key = 'somekey'
351         self.client.get_image_metadata(img_ref, key)
352         self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta/%s' % key))
353
354     @patch('%s.perform_request' % khttp, return_value=FR())
355     def test_shutdown_server(self, PR):
356         vm_id = vm_recv['server']['id']
357         FR.status_code = 202
358         self.client.shutdown_server(vm_id)
359         self.assertEqual(self.client.http_client.url, self.url)
360         self.assertEqual(
361             self.client.http_client.path,
362             '/servers/%s/action' % vm_id)
363         self.assertEqual(
364             PR.call_args[0],
365             ('post',  '{"shutdown": {}}', {}, {}))
366
367     @patch('%s.perform_request' % khttp, return_value=FR())
368     def test_start_server(self, PR):
369         vm_id = vm_recv['server']['id']
370         FR.status_code = 202
371         self.client.start_server(vm_id)
372         self.assertEqual(self.client.http_client.url, self.url)
373         self.assertEqual(
374             self.client.http_client.path,
375             '/servers/%s/action' % vm_id)
376         self.assertEqual(PR.call_args[0], ('post',  '{"start": {}}', {}, {}))
377
378     @patch('%s.perform_request' % khttp, return_value=FR())
379     def test_get_server_console(self, PR):
380         cnsl = dict(console=dict(info1='i1', info2='i2', info3='i3'))
381         FR.json = cnsl
382         vm_id = vm_recv['server']['id']
383         r = self.client.get_server_console(vm_id)
384         self.assertEqual(self.client.http_client.url, self.url)
385         self.assertEqual(
386             self.client.http_client.path,
387             '/servers/%s/action' % vm_id)
388         self.assert_dicts_are_equal(cnsl['console'], r)
389         self.assertEqual(
390             PR.call_args[0],
391             ('post',  '{"console": {"type": "vnc"}}', {}, {}))
392
393     def test_get_firewall_profile(self):
394         vm_id = vm_recv['server']['id']
395         v = 'Some profile'
396         ret = {'attachments': {'values': [{'firewallProfile': v, 1:1}]}}
397         with patch.object(
398                 CycladesClient,
399                 'get_server_details',
400                 return_value=ret) as GSD:
401             r = self.client.get_firewall_profile(vm_id)
402             self.assertEqual(r, v)
403             self.assertEqual(GSD.call_args[0], (vm_id,))
404             ret['attachments']['values'][0].pop('firewallProfile')
405             self.assertRaises(
406                 ClientError,
407                 self.client.get_firewall_profile,
408                 vm_id)
409
410     @patch('%s.perform_request' % khttp, return_value=FR())
411     def test_set_firewall_profile(self, PR):
412         vm_id = vm_recv['server']['id']
413         v = 'Some profile'
414         FR.status_code = 202
415         self.client.set_firewall_profile(vm_id, v)
416         self.assertEqual(self.client.http_client.url, self.url)
417         self.assertEqual(
418             self.client.http_client.path,
419             '/servers/%s/action' % vm_id)
420         self.assertEqual(PR.call_args[0], (
421             'post',
422             '{"firewallProfile": {"profile": "%s"}}' % v,
423             {},
424             {}))
425
426     @patch('%s.perform_request' % khttp, return_value=FR())
427     def test_get_server_stats(self, PR):
428         vm_id = vm_recv['server']['id']
429         stats = dict(stat1='v1', stat2='v2', stat3='v3', stat4='v4')
430         FR.json = dict(stats=stats)
431         r = self.client.get_server_stats(vm_id)
432         self.assertEqual(self.client.http_client.url, self.url)
433         self.assertEqual(
434             self.client.http_client.path,
435             '/servers/%s/stats' % vm_id)
436         self.assert_dicts_are_equal(stats, r)
437
438     @patch('%s.perform_request' % khttp, return_value=FR())
439     def test_create_network(self, PR):
440         net_name = net_send['network']['name']
441         FR.json = net_recv
442         FR.status_code = 202
443         full_args = dict(
444                 cidr='192.168.0.0/24',
445                 gateway='192.168.0.1',
446                 type='MAC_FILTERED',
447                 dhcp=True)
448         test_args = dict(full_args)
449         test_args.update(dict(empty=None, full=None))
450         for arg, val in test_args.items():
451             kwargs = {} if arg == 'empty' else full_args if (
452                 arg == 'full') else {arg: val}
453             r = self.client.create_network(net_name, **kwargs)
454             self.assertEqual(self.client.http_client.url, self.url)
455             self.assertEqual(
456                 self.client.http_client.path,
457                 '/networks')
458             self.assert_dicts_are_equal(r, net_recv['network'])
459             data = PR.call_args[0][1]
460             expected = dict(network=dict(net_send['network']))
461             expected['network'].update(kwargs)
462             self.assert_dicts_are_equal(loads(data), expected)
463
464     @patch('%s.perform_request' % khttp, return_value=FR())
465     def test_connect_server(self, PR):
466         vm_id = vm_recv['server']['id']
467         net_id = net_recv['network']['id']
468         FR.status_code = 202
469         self.client.connect_server(vm_id, net_id)
470         self.assertEqual(self.client.http_client.url, self.url)
471         self.assertEqual(
472             self.client.http_client.path,
473             '/networks/%s/action' % net_id)
474         self.assertEqual(
475             PR.call_args[0],
476             ('post', '{"add": {"serverRef": %s}}' % vm_id, {}, {}))
477
478     @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
479     def test_disconnect_server(self, NP):
480         vm_id = vm_recv['server']['id']
481         net_id = net_recv['network']['id']
482         nic_id = 'nic-%s-%s' % (net_id, vm_id)
483         vm_nics = [
484             dict(id=nic_id, network_id=net_id),
485             dict(id='another-nic-id', network_id='another-net-id'),
486             dict(id=nic_id * 2, network_id=net_id * 2)]
487         with patch.object(
488                 CycladesClient,
489                 'list_server_nics',
490                 return_value=vm_nics) as LSN:
491             r = self.client.disconnect_server(vm_id, nic_id)
492             self.assertEqual(r, 1)
493             self.assertEqual(LSN.call_args[0], (vm_id,))
494             self.assertEqual(NP.call_args[0], (net_id, 'action'))
495             self.assertEqual(
496                 NP.call_args[1],
497                 dict(json_data=dict(remove=dict(attachment=nic_id))))
498
499     @patch('%s.perform_request' % khttp, return_value=FR())
500     def test_list_server_nics(self, PR):
501         vm_id = vm_recv['server']['id']
502         nics = dict(addresses=dict(values=[dict(id='nic1'), dict(id='nic2')]))
503         FR.json = nics
504         r = self.client.list_server_nics(vm_id)
505         self.assertEqual(self.client.http_client.url, self.url)
506         self.assertEqual(
507             self.client.http_client.path,
508             '/servers/%s/ips' % vm_id)
509         expected = nics['addresses']['values']
510         for i in range(len(r)):
511             self.assert_dicts_are_equal(r[i], expected[i])
512
513     @patch('%s.perform_request' % khttp, return_value=FR())
514     def test_list_networks(self, PR):
515         FR.json = net_list
516         r = self.client.list_networks()
517         self.assertEqual(self.client.http_client.url, self.url)
518         self.assertEqual(self.client.http_client.path, '/networks')
519         expected = net_list['networks']['values']
520         for i in range(len(r)):
521             self.assert_dicts_are_equal(expected[i], r[i])
522         self.client.list_networks(detail=True)
523         self.assertEqual(self.client.http_client.url, self.url)
524         self.assertEqual(self.client.http_client.path, '/networks/detail')
525
526     @patch('%s.perform_request' % khttp, return_value=FR())
527     def test_list_network_nics(self, PR):
528         net_id = net_recv['network']['id']
529         FR.json = net_recv
530         r = self.client.list_network_nics(net_id)
531         self.assertEqual(self.client.http_client.url, self.url)
532         self.assertEqual(
533             self.client.http_client.path,
534             '/networks/%s' % net_id)
535         expected = net_recv['network']['attachments']['values']
536         for i in range(len(r)):
537             self.assert_dicts_are_equal(r[i], expected[i])
538
539     @patch('%s.networks_post' % cyclades_pkg, return_value=FR())
540     def test_disconnect_network_nics(self, NP):
541         net_id = net_recv['network']['id']
542         nics = ['nic1', 'nic2', 'nic3']
543         with patch.object(
544                 CycladesClient,
545                 'list_network_nics',
546                 return_value=nics) as lnn:
547             self.client.disconnect_network_nics(net_id)
548             lnn.assert_called_once_with(net_id)
549             for i in range(len(nics)):
550                 expected = call(net_id, 'action', json_data=dict(
551                     remove=dict(attachment=nics[i])))
552                 self.assertEqual(expected, NP.mock_calls[i])
553
554     @patch('%s.perform_request' % khttp, return_value=FR())
555     def test_get_network_details(self, PR):
556         FR.json = net_recv
557         net_id = net_recv['network']['id']
558         r = self.client.get_network_details(net_id)
559         self.assertEqual(self.client.http_client.url, self.url)
560         self.assertEqual(
561             self.client.http_client.path,
562             '/networks/%s' % net_id)
563         self.assert_dicts_are_equal(r, net_recv['network'])
564
565     @patch('%s.perform_request' % khttp, return_value=FR())
566     def test_update_network_name(self, PR):
567         net_id = net_recv['network']['id']
568         new_name = '%s_new' % net_id
569         FR.status_code = 204
570         self.client.update_network_name(net_id, new_name)
571         self.assertEqual(self.client.http_client.url, self.url)
572         self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
573         (method, data, a_headers, a_params) = PR.call_args[0]
574         self.assert_dicts_are_equal(
575             dict(network=dict(name=new_name)),
576             loads(data))
577
578     @patch('%s.perform_request' % khttp, return_value=FR())
579     def test_delete_server(self, PR):
580         vm_id = vm_recv['server']['id']
581         FR.status_code = 204
582         self.client.delete_server(vm_id)
583         self.assertEqual(self.client.http_client.url, self.url)
584         self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
585
586     @patch('%s.perform_request' % khttp, return_value=FR())
587     def test_delete_image(self, PR):
588         FR.status_code = 204
589         self.client.delete_image(img_ref)
590         self.assertEqual(self.client.http_client.url, self.url)
591         self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
592
593     @patch('%s.perform_request' % khttp, return_value=FR())
594     def test_delete_network(self, PR):
595         net_id = net_recv['network']['id']
596         FR.status_code = 204
597         self.client.delete_network(net_id)
598         self.assertEqual(self.client.http_client.url, self.url)
599         self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
600
601     @patch('%s.perform_request' % khttp, return_value=FR())
602     def test_create_image_metadata(self, PR):
603         metadata = dict(m1='v1', m2='v2', m3='v3')
604         FR.json = dict(meta=img_recv['image'])
605         self.assertRaises(
606             ClientError,
607             self.client.create_image_metadata,
608             img_ref, 'key', 'value')
609         FR.status_code = 201
610         for k, v in metadata.items():
611             r = self.client.create_image_metadata(img_ref, k, v)
612             self.assertEqual(self.client.http_client.url, self.url)
613             self.assertEqual(
614                 self.client.http_client.path,
615                 '/images/%s/meta/%s' % (img_ref, k))
616             (method, data, a_headers, a_params) = PR.call_args[0]
617             self.assertEqual(dict(meta={k: v}), loads(data))
618             self.assert_dicts_are_equal(r, img_recv['image'])
619
620     @patch('%s.images_post' % cyclades_pkg, return_value=FR())
621     def test_update_image_metadata(self, images_post):
622         metadata = dict(m1='v1', m2='v2', m3='v3')
623         FR.json = dict(metadata=metadata)
624         r = self.client.update_image_metadata(img_ref, **metadata)
625         self.assert_dicts_are_equal(r, metadata)
626         (called_id, cmd) = images_post.call_args[0]
627         self.assertEqual(called_id, img_ref)
628         self.assertEqual(cmd, 'meta')
629         data = images_post.call_args[1]['json_data']
630         self.assert_dicts_are_equal(data, dict(metadata=metadata))
631
632     @patch('%s.images_delete' % cyclades_pkg, return_value=FR())
633     def test_delete_image_metadata(self, images_delete):
634         key = 'metakey'
635         self.client.delete_image_metadata(img_ref, key)
636         self.assertEqual(
637             (img_ref, '/meta/' + key),
638             images_delete.call_args[0])
639
640 if __name__ == '__main__':
641     from sys import argv
642     from kamaki.clients.test import runTestCase
643     runTestCase(Cyclades, 'Cyclades (multi) Client', argv[1:])