Finetest and move Compute.get_server_metadata
[kamaki] / kamaki / clients / compute / 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
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 compute_pkg_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     @patch('%s.servers_post' % compute_pkg, return_value=FR())
211     def test_reboot_server(self, SP):
212         vm_id = vm_recv['server']['id']
213         for hard in (None, True):
214             self.client.reboot_server(vm_id, hard=hard)
215             self.assertEqual(SP.mock_calls[-1], call(
216                 vm_id, 'action',
217                 json_data=dict(reboot=dict(type='HARD' if hard else 'SOFT'))))
218
219     @patch('%s.servers_put' % compute_pkg, return_value=FR())
220     def test_create_server_metadata(self, SP):
221         vm_id = vm_recv['server']['id']
222         metadata = dict(m1='v1', m2='v2', m3='v3')
223         FR.json = dict(meta=vm_recv['server'])
224         for k, v in metadata.items():
225             r = self.client.create_server_metadata(vm_id, k, v)
226             self.assert_dicts_are_equal(r, vm_recv['server'])
227             self.assertEqual(SP.mock_calls[-1], call(
228                 vm_id, 'meta/%s' % k,
229                 json_data=dict(meta={k: v}), success=201))
230
231     @patch('%s.servers_get' % compute_pkg, return_value=FR())
232     def test_get_server_metadata(self, SG):
233         vm_id = vm_recv['server']['id']
234         metadata = dict(m1='v1', m2='v2', m3='v3')
235         FR.json = dict(metadata=dict(values=metadata))
236         r = self.client.get_server_metadata(vm_id)
237         self.assertEqual(SG.mock_calls[-1], call(vm_id, '/meta'))
238         self.assert_dicts_are_equal(r, metadata)
239
240         for k, v in metadata.items():
241             FR.json = dict(meta={k: v})
242             r = self.client.get_server_metadata(vm_id, k)
243             self.assert_dicts_are_equal(r, {k: v})
244             self.assertEqual(SG.mock_calls[-1], call(vm_id, '/meta/%s' % k))
245
246     """
247     @patch('%s.servers_post' % compute_pkg, return_value=FR())
248     def test_update_server_metadata(self, servers_post):
249         vm_id = vm_recv['server']['id']
250         metadata = dict(m1='v1', m2='v2', m3='v3')
251         FR.json = dict(metadata=metadata)
252         r = self.client.update_server_metadata(vm_id, **metadata)
253         self.assert_dicts_are_equal(r, metadata)
254         (called_id, cmd) = servers_post.call_args[0]
255         self.assertEqual(called_id, vm_id)
256         self.assertEqual(cmd, 'meta')
257         data = servers_post.call_args[1]['json_data']
258         self.assert_dicts_are_equal(data, dict(metadata=metadata))
259
260     @patch('%s.servers_delete' % compute_pkg, return_value=FR())
261     def test_delete_server_metadata(self, servers_delete):
262         vm_id = vm_recv['server']['id']
263         key = 'metakey'
264         self.client.delete_server_metadata(vm_id, key)
265         self.assertEqual((vm_id, 'meta/' + key), servers_delete.call_args[0])
266
267     @patch('%s.perform_request' % compute_pkg, return_value=FR())
268     def test_list_flavors(self, PR):
269         FR.json = flavor_list
270         r = self.client.list_flavors()
271         self.assertEqual(self.client.http_client.url, self.url)
272         self.assertEqual(self.client.http_client.path, '/flavors')
273         (method, data, a_headers, a_params) = PR.call_args[0]
274         self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
275         r = self.client.list_flavors(detail=True)
276         self.assertEqual(self.client.http_client.url, self.url)
277         self.assertEqual(self.client.http_client.path, '/flavors/detail')
278
279     @patch('%s.perform_request' % compute_pkg, return_value=FR())
280     def test_get_flavor_details(self, PR):
281         FR.json = dict(flavor=flavor_list['flavors'])
282         r = self.client.get_flavor_details(fid)
283         self.assertEqual(self.client.http_client.url, self.url)
284         self.assertEqual(self.client.http_client.path, '/flavors/%s' % fid)
285         self.assert_dicts_are_equal(r, flavor_list['flavors'])
286
287     @patch('%s.perform_request' % compute_pkg, return_value=FR())
288     def test_list_images(self, PR):
289         FR.json = img_list
290         r = self.client.list_images()
291         self.assertEqual(self.client.http_client.url, self.url)
292         self.assertEqual(self.client.http_client.path, '/images')
293         expected = img_list['images']['values']
294         for i in range(len(r)):
295             self.assert_dicts_are_equal(expected[i], r[i])
296         self.client.list_images(detail=True)
297         self.assertEqual(self.client.http_client.url, self.url)
298         self.assertEqual(self.client.http_client.path, '/images/detail')
299
300     @patch('%s.perform_request' % compute_pkg, return_value=FR())
301     def test_get_image_details(self, PR):
302         FR.json = img_recv
303         r = self.client.get_image_details(img_ref)
304         self.assertEqual(self.client.http_client.url, self.url)
305         self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
306         self.assert_dicts_are_equal(r, img_recv['image'])
307
308     @patch('%s.images_get' % compute_pkg, return_value=FR())
309     def test_get_image_metadata(self, IG):
310         FR.json = dict(metadata=dict(values=img_recv['image']))
311         r = self.client.get_image_metadata(img_ref)
312         self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta'))
313         self.assert_dicts_are_equal(img_recv['image'], r)
314         FR.json = dict(meta=img_recv['image'])
315         key = 'somekey'
316         self.client.get_image_metadata(img_ref, key)
317         self.assertEqual(IG.call_args[0], ('%s' % img_ref, '/meta/%s' % key))
318
319     @patch('%s.perform_request' % compute_pkg, return_value=FR())
320     def test_shutdown_server(self, PR):
321         vm_id = vm_recv['server']['id']
322         FR.status_code = 202
323         self.client.shutdown_server(vm_id)
324         self.assertEqual(self.client.http_client.url, self.url)
325         self.assertEqual(
326             self.client.http_client.path,
327             '/servers/%s/action' % vm_id)
328         self.assertEqual(
329             PR.call_args[0],
330             ('post',  '{"shutdown": {}}', {}, {}))
331
332     @patch('%s.perform_request' % compute_pkg, return_value=FR())
333     def test_start_server(self, PR):
334         vm_id = vm_recv['server']['id']
335         FR.status_code = 202
336         self.client.start_server(vm_id)
337         self.assertEqual(self.client.http_client.url, self.url)
338         self.assertEqual(
339             self.client.http_client.path,
340             '/servers/%s/action' % vm_id)
341         self.assertEqual(PR.call_args[0], ('post',  '{"start": {}}', {}, {}))
342
343     @patch('%s.perform_request' % compute_pkg, return_value=FR())
344     def test_get_server_console(self, PR):
345         cnsl = dict(console=dict(info1='i1', info2='i2', info3='i3'))
346         FR.json = cnsl
347         vm_id = vm_recv['server']['id']
348         r = self.client.get_server_console(vm_id)
349         self.assertEqual(self.client.http_client.url, self.url)
350         self.assertEqual(
351             self.client.http_client.path,
352             '/servers/%s/action' % vm_id)
353         self.assert_dicts_are_equal(cnsl['console'], r)
354         self.assertEqual(
355             PR.call_args[0],
356             ('post',  '{"console": {"type": "vnc"}}', {}, {}))
357
358     def test_get_firewall_profile(self):
359         vm_id = vm_recv['server']['id']
360         v = 'Some profile'
361         ret = {'attachments': {'values': [{'firewallProfile': v, 1:1}]}}
362         with patch.object(
363                 CycladesClient,
364                 'get_server_details',
365                 return_value=ret) as GSD:
366             r = self.client.get_firewall_profile(vm_id)
367             self.assertEqual(r, v)
368             self.assertEqual(GSD.call_args[0], (vm_id,))
369             ret['attachments']['values'][0].pop('firewallProfile')
370             self.assertRaises(
371                 ClientError,
372                 self.client.get_firewall_profile,
373                 vm_id)
374
375     @patch('%s.perform_request' % compute_pkg, return_value=FR())
376     def test_set_firewall_profile(self, PR):
377         vm_id = vm_recv['server']['id']
378         v = 'Some profile'
379         FR.status_code = 202
380         self.client.set_firewall_profile(vm_id, v)
381         self.assertEqual(self.client.http_client.url, self.url)
382         self.assertEqual(
383             self.client.http_client.path,
384             '/servers/%s/action' % vm_id)
385         self.assertEqual(PR.call_args[0], (
386             'post',
387             '{"firewallProfile": {"profile": "%s"}}' % v,
388             {},
389             {}))
390
391     @patch('%s.perform_request' % compute_pkg, return_value=FR())
392     def test_get_server_stats(self, PR):
393         vm_id = vm_recv['server']['id']
394         stats = dict(stat1='v1', stat2='v2', stat3='v3', stat4='v4')
395         FR.json = dict(stats=stats)
396         r = self.client.get_server_stats(vm_id)
397         self.assertEqual(self.client.http_client.url, self.url)
398         self.assertEqual(
399             self.client.http_client.path,
400             '/servers/%s/stats' % vm_id)
401         self.assert_dicts_are_equal(stats, r)
402
403     @patch('%s.perform_request' % compute_pkg, return_value=FR())
404     def test_create_network(self, PR):
405         net_name = net_send['network']['name']
406         FR.json = net_recv
407         FR.status_code = 202
408         full_args = dict(
409                 cidr='192.168.0.0/24',
410                 gateway='192.168.0.1',
411                 type='MAC_FILTERED',
412                 dhcp=True)
413         test_args = dict(full_args)
414         test_args.update(dict(empty=None, full=None))
415         for arg, val in test_args.items():
416             kwargs = {} if arg == 'empty' else full_args if (
417                 arg == 'full') else {arg: val}
418             r = self.client.create_network(net_name, **kwargs)
419             self.assertEqual(self.client.http_client.url, self.url)
420             self.assertEqual(
421                 self.client.http_client.path,
422                 '/networks')
423             self.assert_dicts_are_equal(r, net_recv['network'])
424             data = PR.call_args[0][1]
425             expected = dict(network=dict(net_send['network']))
426             expected['network'].update(kwargs)
427             self.assert_dicts_are_equal(loads(data), expected)
428
429     @patch('%s.perform_request' % compute_pkg, return_value=FR())
430     def test_connect_server(self, PR):
431         vm_id = vm_recv['server']['id']
432         net_id = net_recv['network']['id']
433         FR.status_code = 202
434         self.client.connect_server(vm_id, net_id)
435         self.assertEqual(self.client.http_client.url, self.url)
436         self.assertEqual(
437             self.client.http_client.path,
438             '/networks/%s/action' % net_id)
439         self.assertEqual(
440             PR.call_args[0],
441             ('post', '{"add": {"serverRef": %s}}' % vm_id, {}, {}))
442
443     @patch('%s.networks_post' % compute_pkg, return_value=FR())
444     def test_disconnect_server(self, NP):
445         vm_id = vm_recv['server']['id']
446         net_id = net_recv['network']['id']
447         nic_id = 'nic-%s-%s' % (net_id, vm_id)
448         vm_nics = [
449             dict(id=nic_id, network_id=net_id),
450             dict(id='another-nic-id', network_id='another-net-id'),
451             dict(id=nic_id * 2, network_id=net_id * 2)]
452         with patch.object(
453                 CycladesClient,
454                 'list_server_nics',
455                 return_value=vm_nics) as LSN:
456             r = self.client.disconnect_server(vm_id, nic_id)
457             self.assertEqual(r, 1)
458             self.assertEqual(LSN.call_args[0], (vm_id,))
459             self.assertEqual(NP.call_args[0], (net_id, 'action'))
460             self.assertEqual(
461                 NP.call_args[1],
462                 dict(json_data=dict(remove=dict(attachment=nic_id))))
463
464     @patch('%s.perform_request' % compute_pkg, return_value=FR())
465     def test_list_server_nics(self, PR):
466         vm_id = vm_recv['server']['id']
467         nics = dict(addresses=dict(values=[dict(id='nic1'), dict(id='nic2')]))
468         FR.json = nics
469         r = self.client.list_server_nics(vm_id)
470         self.assertEqual(self.client.http_client.url, self.url)
471         self.assertEqual(
472             self.client.http_client.path,
473             '/servers/%s/ips' % vm_id)
474         expected = nics['addresses']['values']
475         for i in range(len(r)):
476             self.assert_dicts_are_equal(r[i], expected[i])
477
478     @patch('%s.perform_request' % compute_pkg, return_value=FR())
479     def test_list_networks(self, PR):
480         FR.json = net_list
481         r = self.client.list_networks()
482         self.assertEqual(self.client.http_client.url, self.url)
483         self.assertEqual(self.client.http_client.path, '/networks')
484         expected = net_list['networks']['values']
485         for i in range(len(r)):
486             self.assert_dicts_are_equal(expected[i], r[i])
487         self.client.list_networks(detail=True)
488         self.assertEqual(self.client.http_client.url, self.url)
489         self.assertEqual(self.client.http_client.path, '/networks/detail')
490
491     @patch('%s.perform_request' % compute_pkg, return_value=FR())
492     def test_list_network_nics(self, PR):
493         net_id = net_recv['network']['id']
494         FR.json = net_recv
495         r = self.client.list_network_nics(net_id)
496         self.assertEqual(self.client.http_client.url, self.url)
497         self.assertEqual(
498             self.client.http_client.path,
499             '/networks/%s' % net_id)
500         expected = net_recv['network']['attachments']['values']
501         for i in range(len(r)):
502             self.assert_dicts_are_equal(r[i], expected[i])
503
504     @patch('%s.networks_post' % compute_pkg, return_value=FR())
505     def test_disconnect_network_nics(self, NP):
506         net_id = net_recv['network']['id']
507         nics = ['nic1', 'nic2', 'nic3']
508         with patch.object(
509                 CycladesClient,
510                 'list_network_nics',
511                 return_value=nics) as lnn:
512             self.client.disconnect_network_nics(net_id)
513             lnn.assert_called_once_with(net_id)
514             for i in range(len(nics)):
515                 expected = call(net_id, 'action', json_data=dict(
516                     remove=dict(attachment=nics[i])))
517                 self.assertEqual(expected, NP.mock_calls[i])
518
519     @patch('%s.perform_request' % compute_pkg, return_value=FR())
520     def test_get_network_details(self, PR):
521         FR.json = net_recv
522         net_id = net_recv['network']['id']
523         r = self.client.get_network_details(net_id)
524         self.assertEqual(self.client.http_client.url, self.url)
525         self.assertEqual(
526             self.client.http_client.path,
527             '/networks/%s' % net_id)
528         self.assert_dicts_are_equal(r, net_recv['network'])
529
530     @patch('%s.perform_request' % compute_pkg, return_value=FR())
531     def test_update_network_name(self, PR):
532         net_id = net_recv['network']['id']
533         new_name = '%s_new' % net_id
534         FR.status_code = 204
535         self.client.update_network_name(net_id, new_name)
536         self.assertEqual(self.client.http_client.url, self.url)
537         self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
538         (method, data, a_headers, a_params) = PR.call_args[0]
539         self.assert_dicts_are_equal(
540             dict(network=dict(name=new_name)),
541             loads(data))
542
543     @patch('%s.perform_request' % compute_pkg, return_value=FR())
544     def test_delete_server(self, PR):
545         vm_id = vm_recv['server']['id']
546         FR.status_code = 204
547         self.client.delete_server(vm_id)
548         self.assertEqual(self.client.http_client.url, self.url)
549         self.assertEqual(self.client.http_client.path, '/servers/%s' % vm_id)
550
551     @patch('%s.perform_request' % compute_pkg, return_value=FR())
552     def test_delete_image(self, PR):
553         FR.status_code = 204
554         self.client.delete_image(img_ref)
555         self.assertEqual(self.client.http_client.url, self.url)
556         self.assertEqual(self.client.http_client.path, '/images/%s' % img_ref)
557
558     @patch('%s.perform_request' % compute_pkg, return_value=FR())
559     def test_delete_network(self, PR):
560         net_id = net_recv['network']['id']
561         FR.status_code = 204
562         self.client.delete_network(net_id)
563         self.assertEqual(self.client.http_client.url, self.url)
564         self.assertEqual(self.client.http_client.path, '/networks/%s' % net_id)
565
566     @patch('%s.perform_request' % compute_pkg, return_value=FR())
567     def test_create_image_metadata(self, PR):
568         metadata = dict(m1='v1', m2='v2', m3='v3')
569         FR.json = dict(meta=img_recv['image'])
570         self.assertRaises(
571             ClientError,
572             self.client.create_image_metadata,
573             img_ref, 'key', 'value')
574         FR.status_code = 201
575         for k, v in metadata.items():
576             r = self.client.create_image_metadata(img_ref, k, v)
577             self.assertEqual(self.client.http_client.url, self.url)
578             self.assertEqual(
579                 self.client.http_client.path,
580                 '/images/%s/meta/%s' % (img_ref, k))
581             (method, data, a_headers, a_params) = PR.call_args[0]
582             self.assertEqual(dict(meta={k: v}), loads(data))
583             self.assert_dicts_are_equal(r, img_recv['image'])
584
585     @patch('%s.images_post' % compute_pkg, return_value=FR())
586     def test_update_image_metadata(self, images_post):
587         metadata = dict(m1='v1', m2='v2', m3='v3')
588         FR.json = dict(metadata=metadata)
589         r = self.client.update_image_metadata(img_ref, **metadata)
590         self.assert_dicts_are_equal(r, metadata)
591         (called_id, cmd) = images_post.call_args[0]
592         self.assertEqual(called_id, img_ref)
593         self.assertEqual(cmd, 'meta')
594         data = images_post.call_args[1]['json_data']
595         self.assert_dicts_are_equal(data, dict(metadata=metadata))
596
597     @patch('%s.images_delete' % compute_pkg, return_value=FR())
598     def test_delete_image_metadata(self, images_delete):
599         key = 'metakey'
600         self.client.delete_image_metadata(img_ref, key)
601         self.assertEqual(
602             (img_ref, '/meta/' + key),
603             images_delete.call_args[0])
604     """
605
606 if __name__ == '__main__':
607     from sys import argv
608     from kamaki.clients.test import runTestCase
609     runTestCase(Cyclades, 'Cyclades (multi) Client', argv[1:])