Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / test / cyclades.py @ 278f2eb3

History | View | Annotate | Download (23.6 kB)

1
# Copyright 2012-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
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

    
96

    
97
class Cyclades(TestCase):
98

    
99
    def assert_dicts_are_equal(self, d1, d2):
100
        for k, v in d1.items():
101
            self.assertTrue(k in d2)
102
            if isinstance(v, dict):
103
                self.assert_dicts_are_equal(v, d2[k])
104
            else:
105
                self.assertEqual(unicode(v), unicode(d2[k]))
106

    
107
    class FR(object):
108
        """FR stands for Fake Response"""
109
        json = vm_recv
110
        headers = {}
111
        content = json
112
        status = None
113
        status_code = 200
114

    
115
        def release(self):
116
            pass
117

    
118
    """Set up a Cyclades thorough test"""
119
    def setUp(self):
120
        self.url = 'http://cyclades.example.com'
121
        self.token = 'cyc14d3s70k3n'
122
        self.client = CycladesClient(self.url, self.token)
123
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
124
        self.C = KamakiHTTPConnection
125

    
126
    def tearDown(self):
127
        self.FR.status_code = 200
128
        self.FR.json = vm_recv
129

    
130
    def test_create_server(self):
131
        self.client.get_image_details = Mock(return_value=img_recv['image'])
132
        with patch.object(Client, 'request', side_effect=ClientError(
133
                'REQUEST ENTITY TOO LARGE',
134
                status=403)):
135
            self.assertRaises(
136
                ClientError,
137
                self.client.create_server,
138
                vm_name, fid, img_ref)
139

    
140
        with patch.object(
141
                self.C,
142
                'perform_request',
143
                return_value=self.FR()) as perform_req:
144
            self.assertRaises(
145
                ClientError,
146
                self.client.create_server,
147
                vm_name, fid, img_ref)
148
            self.FR.status_code = 202
149
            r = self.client.create_server(vm_name, fid, img_ref)
150
            self.assertEqual(self.client.http_client.url, self.url)
151
            self.assertEqual(self.client.http_client.path, '/servers')
152
            (method, data, a_headers, a_params) = perform_req.call_args[0]
153
            self.assert_dicts_are_equal(loads(data), vm_send)
154
            self.assert_dicts_are_equal(r, vm_recv['server'])
155
            prsn = 'Personality string (does not work with real servers)'
156
            self.client.create_server(vm_name, fid, img_ref, prsn)
157
            (method, data, a_headers, a_params) = perform_req.call_args[0]
158
            data = loads(data)
159
            self.assertTrue('personality' in data['server'])
160
            self.assertEqual(prsn, data['server']['personality'])
161

    
162
    def test_list_servers(self):
163
        self.FR.json = vm_list
164
        with patch.object(
165
                self.C,
166
                'perform_request',
167
                return_value=self.FR()) as perform_req:
168
            r = self.client.list_servers()
169
            self.assertEqual(self.client.http_client.url, self.url)
170
            self.assertEqual(self.client.http_client.path, '/servers')
171
            (method, data, a_headers, a_params) = perform_req.call_args[0]
172
            self.assert_dicts_are_equal(dict(values=r), vm_list['servers'])
173
            r = self.client.list_servers(detail=True)
174
            self.assertEqual(self.client.http_client.url, self.url)
175
            self.assertEqual(self.client.http_client.path, '/servers/detail')
176
        with patch.object(
177
                CycladesClientApi,
178
                'servers_get',
179
                return_value=self.FR()) as servers_get:
180
            self.client.list_servers(changes_since=True)
181
            self.assertTrue(servers_get.call_args[1]['changes_since'])
182

    
183
    def test_get_server_details(self):
184
        vm_id = vm_recv['server']['id']
185
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
186
            r = self.client.get_server_details(vm_id)
187
            self.assertEqual(self.client.http_client.url, self.url)
188
            self.assertEqual(
189
                self.client.http_client.path,
190
                '/servers/%s' % vm_id)
191
            self.assert_dicts_are_equal(r, vm_recv['server'])
192

    
193
    def test_update_server_name(self):
194
        vm_id = vm_recv['server']['id']
195
        new_name = vm_name + '_new'
196
        self.FR.status_code = 204
197
        with patch.object(
198
                self.C,
199
                'perform_request',
200
                return_value=self.FR()) as perform_req:
201
            self.client.update_server_name(vm_id, new_name)
202
            self.assertEqual(self.client.http_client.url, self.url)
203
            self.assertEqual(
204
                self.client.http_client.path,
205
                '/servers/%s' % vm_id)
206
            (method, data, a_headers, a_params) = perform_req.call_args[0]
207
            self.assert_dicts_are_equal(
208
                dict(server=dict(name=new_name)),
209
                loads(data))
210

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

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

    
251
    def test_get_server_metadata(self):
252
        vm_id = vm_recv['server']['id']
253
        metadata = dict(m1='v1', m2='v2', m3='v3')
254
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
255
            self.FR.json = dict(metadata=dict(values=metadata))
256
            r = self.client.get_server_metadata(vm_id)
257
            self.assertEqual(self.client.http_client.url, self.url)
258
            self.assertEqual(
259
                self.client.http_client.path,
260
                '/servers/%s/meta' % vm_id)
261
            self.assert_dicts_are_equal(r, metadata)
262

    
263
            for k, v in metadata.items():
264
                self.FR.json = dict(meta={k: v})
265
                r = self.client.get_server_metadata(vm_id, k)
266
                self.assertEqual(self.client.http_client.url, self.url)
267
                self.assertEqual(
268
                    self.client.http_client.path,
269
                    '/servers/%s/meta/%s' % (vm_id, k))
270
                self.assert_dicts_are_equal(r, {k: v})
271

    
272
    def test_update_server_metadata(self):
273
        vm_id = vm_recv['server']['id']
274
        metadata = dict(m1='v1', m2='v2', m3='v3')
275
        self.FR.json = dict(metadata=metadata)
276
        with patch.object(
277
                CycladesClientApi,
278
                'servers_post',
279
                return_value=self.FR()) as servers_post:
280
            r = self.client.update_server_metadata(vm_id, **metadata)
281
            self.assert_dicts_are_equal(r, metadata)
282
            (called_id, cmd) = servers_post.call_args[0]
283
            self.assertEqual(called_id, vm_id)
284
            self.assertEqual(cmd, 'meta')
285
            data = servers_post.call_args[1]['json_data']
286
            self.assert_dicts_are_equal(data, dict(metadata=metadata))
287

    
288
    def test_delete_server_metadata(self):
289
        vm_id = vm_recv['server']['id']
290
        key = 'metakey'
291
        with patch.object(
292
                CycladesClientApi,
293
                'servers_delete',
294
                return_value=self.FR()) as servers_delete:
295
            self.client.delete_server_metadata(vm_id, key)
296
            self.assertEqual(
297
                (vm_id, 'meta/' + key),
298
                servers_delete.call_args[0])
299

    
300
    def test_list_flavors(self):
301
        self.FR.json = flavor_list
302
        with patch.object(
303
                self.C,
304
                'perform_request',
305
                return_value=self.FR()) as perform_req:
306
            r = self.client.list_flavors()
307
            self.assertEqual(self.client.http_client.url, self.url)
308
            self.assertEqual(self.client.http_client.path, '/flavors')
309
            (method, data, a_headers, a_params) = perform_req.call_args[0]
310
            self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
311
            r = self.client.list_flavors(detail=True)
312
            self.assertEqual(self.client.http_client.url, self.url)
313
            self.assertEqual(self.client.http_client.path, '/flavors/detail')
314

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

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

    
338
    def test_get_image_details(self):
339
        self.FR.json = img_recv
340
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
341
            r = self.client.get_image_details(img_ref)
342
            self.assertEqual(self.client.http_client.url, self.url)
343
            self.assertEqual(
344
                self.client.http_client.path,
345
                '/images/%s' % img_ref)
346
            self.assert_dicts_are_equal(r, img_recv['image'])
347

    
348
    def test_get_image_metadata(self):
349
        self.FR.json = dict(metadata=dict(values=img_recv['image']))
350
        with patch.object(
351
                CycladesClient,
352
                'images_get',
353
                return_value=self.FR()) as inner:
354
            r = self.client.get_image_metadata(img_ref)
355
            self.assertEqual(inner.call_args[0], ('%s' % img_ref, '/meta'))
356
            self.assert_dicts_are_equal(img_recv['image'], r)
357
            self.FR.json = dict(meta=img_recv['image'])
358
            key = 'somekey'
359
            self.client.get_image_metadata(img_ref, key)
360
            self.assertEqual(
361
                inner.call_args[0],
362
                ('%s' % img_ref, '/meta/%s' % key))
363

    
364
    def test_shutdown_server(self):
365
        vm_id = vm_recv['server']['id']
366
        self.FR.status_code = 202
367
        with patch.object(
368
                self.C,
369
                'perform_request',
370
                return_value=self.FR()) as perform_req:
371
            self.client.shutdown_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(
377
                perform_req.call_args[0],
378
                ('post',  '{"shutdown": {}}', {}, {}))
379

    
380
    def test_start_server(self):
381
        vm_id = vm_recv['server']['id']
382
        self.FR.status_code = 202
383
        with patch.object(
384
                self.C,
385
                'perform_request',
386
                return_value=self.FR()) as perform_req:
387
            self.client.start_server(vm_id)
388
            self.assertEqual(self.client.http_client.url, self.url)
389
            self.assertEqual(
390
                self.client.http_client.path,
391
                '/servers/%s/action' % vm_id)
392
            self.assertEqual(
393
                perform_req.call_args[0],
394
                ('post',  '{"start": {}}', {}, {}))
395

    
396
    def test_get_server_console(self):
397
        cnsl = dict(console=dict(info1='i1', info2='i2', info3='i3'))
398
        self.FR.json = cnsl
399
        vm_id = vm_recv['server']['id']
400
        with patch.object(
401
                self.C,
402
                'perform_request',
403
                return_value=self.FR()) as perform_req:
404
            r = self.client.get_server_console(vm_id)
405
            self.assertEqual(self.client.http_client.url, self.url)
406
            self.assertEqual(
407
                self.client.http_client.path,
408
                '/servers/%s/action' % vm_id)
409
            self.assert_dicts_are_equal(cnsl['console'], r)
410
            self.assertEqual(
411
                perform_req.call_args[0],
412
                ('post',  '{"console": {"type": "vnc"}}', {}, {}))
413

    
414
    def test_get_firewall_profile(self):
415
        vm_id = vm_recv['server']['id']
416
        v = 'Some profile'
417
        ret = {'attachments': {'values': [{'firewallProfile': v, 1:1}]}}
418
        with patch.object(
419
                CycladesClient,
420
                'get_server_details',
421
                return_value=ret) as gsd:
422
            r = self.client.get_firewall_profile(vm_id)
423
            self.assertEqual(r, v)
424
            self.assertEqual(gsd.call_args[0], (vm_id,))
425
            ret['attachments']['values'][0].pop('firewallProfile')
426
            self.assertRaises(
427
                ClientError,
428
                self.client.get_firewall_profile,
429
                vm_id)
430

    
431
    def test_set_firewall_profile(self):
432
        vm_id = vm_recv['server']['id']
433
        v = 'Some profile'
434
        self.FR.status_code = 202
435
        with patch.object(
436
                self.C,
437
                'perform_request',
438
                return_value=self.FR()) as perform_req:
439
            self.client.set_firewall_profile(vm_id, v)
440
            self.assertEqual(self.client.http_client.url, self.url)
441
            self.assertEqual(
442
                self.client.http_client.path,
443
                '/servers/%s/action' % vm_id)
444
            self.assertEqual(perform_req.call_args[0], (
445
                'post',
446
                '{"firewallProfile": {"profile": "%s"}}' % v,
447
                {},
448
                {}))
449

    
450
    """
451
    def test_get_server_stats(self):
452
        r = self.client.get_server_stats(self.server1['id'])
453
        it = ('cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries', 'refresh')
454
        for term in it:
455
            self.assertTrue(term in r)
456

457
    def test_create_network(self):
458
        print('\twith no params')
459
        self.network1 = self._create_network(self.netname1)
460
        self._wait_for_network(self.network1['id'], 'ACTIVE')
461
        n1id = self.network1['id']
462
        self.network1 = self.client.get_network_details(n1id)
463
        nets = self.client.list_networks(self.network1['id'])
464
        chosen = [net for net in nets if net['id'] == n1id][0]
465
        chosen.pop('updated')
466
        net1 = dict(self.network1)
467
        net1.pop('updated')
468
        self.assert_dicts_are_equal(chosen, net1)
469
        for param, val in dict(
470
                cidr='192.168.0.0/24',
471
                gateway='192.168.0.1',
472
                type='MAC_FILTERED',
473
                dhcp=True).items():
474
            print('\tdelete %s to avoid max net limit' % n1id)
475
            self._delete_network(n1id)
476
            kwargs = {param: val}
477
            print('\twith %s=%s' % (param, val))
478
            self.network1 = self._create_network(self.netname1, **kwargs)
479
            n1id = self.network1['id']
480
            self._wait_for_network(n1id, 'ACTIVE')
481
            self.network1 = self.client.get_network_details(n1id)
482
            self.assertEqual(self.network1[param], val)
483

484
    def test_connect_server(self):
485
        self.client.connect_server(self.server1['id'], self.network1['id'])
486
        self.assertTrue(self._wait_for_nic(
487
            self.network1['id'],
488
            self.server1['id']))
489

490
    def test_disconnect_server(self):
491
        self.client.disconnect_server(self.server1['id'], self.network1['id'])
492
        self.assertTrue(self._wait_for_nic(
493
            self.network1['id'],
494
            self.server1['id'],
495
            in_creation=False))
496

497
    def _test_0260_wait_for_second_network(self):
498
        self.server1 = self._create_server(
499
            self.servname1,
500
            self.flavorid,
501
            self.img)
502
        self.network2 = self._create_network(self.netname2)
503
        self._wait_for_status(self.server1['id'], 'BUILD')
504
        self._wait_for_network(self.network2['id'], 'ACTIVE')
505
        self._test_0280_list_server_nics()
506

507
    def _test_0280_list_server_nics(self):
508
        r = self.client.list_server_nics(self.server1['id'])
509
        len0 = len(r)
510
        self.client.connect_server(self.server1['id'], self.network2['id'])
511
        self.assertTrue(self._wait_for_nic(
512
            self.network2['id'],
513
            self.server1['id']))
514
        r = self.client.list_server_nics(self.server1['id'])
515
        self.assertTrue(len(r) > len0)
516

517
    def test_list_networks(self):
518
        r = self.client.list_networks()
519
        self.assertTrue(len(r) > 1)
520
        ids = [net['id'] for net in r]
521
        names = [net['name'] for net in r]
522
        self.assertTrue('1' in ids)
523
        #self.assertTrue('public' in names)
524
        self.assertTrue(self.network1['id'] in ids)
525
        self.assertTrue(self.network1['name'] in names)
526

527
        r = self.client.list_networks(detail=True)
528
        ids = [net['id'] for net in r]
529
        names = [net['name'] for net in r]
530
        for net in r:
531
            self.assertTrue(net['id'] in ids)
532
            self.assertTrue(net['name'] in names)
533
            for term in ('status', 'updated', 'created'):
534
                self.assertTrue(term in net.keys())
535

536
    def test_get_network_details(self):
537
        r = self.client.get_network_details(self.network1['id'])
538
        net1 = dict(self.network1)
539
        net1.pop('status')
540
        net1.pop('updated', None)
541
        net1.pop('attachments')
542
        r.pop('status')
543
        r.pop('updated', None)
544
        r.pop('attachments')
545
        self.assert_dicts_are_equal(net1, r)
546

547
    def test_update_network_name(self):
548
        updated_name = self.netname2 + '_upd'
549
        self.client.update_network_name(self.network2['id'], updated_name)
550

551
        def netwait(wait):
552
            r = self.client.get_network_details(self.network2['id'])
553
            if r['name'] == updated_name:
554
                return
555
            time.sleep(wait)
556
        self.do_with_progress_bar(
557
            netwait,
558
            'Network %s name is changing:' % self.network2['id'],
559
            self._waits[:5])
560

561
        r = self.client.get_network_details(self.network2['id'])
562
        self.assertEqual(r['name'], updated_name)
563

564
    def test_delete_image(self):
565
        images = self.client.list_images()
566
        self.client.delete_image(images[2]['id'])
567
        try:
568
            r = self.client.get_image_details(images[2]['id'], success=(400))
569
        except ClientError as err:
570
            self.assertEqual(err.status, 404)
571

572
    def test_create_image_metadata(self):
573
        r = self.client.create_image_metadata(self.img, 'mykey', 'myval')
574
        self.assertEqual(r['mykey'], 'myval')
575

576
    def test_update_image_metadata(self):
577
        r = self.client.create_image_metadata(self.img, 'mykey0', 'myval')
578
        r = self.client.update_image_metadata(self.img, 'mykey0', 'myval0')
579
        self.assertEqual(r['mykey0'], 'myval0')
580

581
    def test_delete_image_metadata(self):
582
        self.client.create_image_metadata(self.img, 'mykey1', 'myval1')
583
        self.client.delete_image_metadata(self.img, 'mykey1')
584
        r = self.client.get_image_metadata(self.img)
585
        self.assertNotEqual('mykey1' in r)
586
    """