Statistics
| Branch: | Tag: | Revision:

root / api / tests.py @ 529178b1

History | View | Annotate | Download (30.4 kB)

1
#
2
# Copyright (c) 2010 Greek Research and Technology Network
3
#
4

    
5
from __future__ import with_statement
6

    
7
from collections import defaultdict
8
from email.utils import parsedate
9
from random import choice, randint, sample
10
from time import mktime
11

    
12
import datetime
13

    
14
from django.utils import simplejson as json
15
from django.test import TestCase
16
from django.test.client import Client
17

    
18
#from synnefo.api.tests_auth import AuthTestCase
19
from synnefo.db.models import *
20
from synnefo.logic import utils
21

    
22

    
23
class APITestCase(TestCase):
24
    fixtures = ['api_test_data']
25
    test_server_id = 1001
26
    test_image_id = 1
27
    test_flavor_id = 1
28
    test_group_id = 1
29
    test_wrong_server_id = 99999999
30
    test_wrong_image_id = 99999999
31
    test_wrong_flavor_id = 99999999
32
    test_wrong_group_id = 99999999
33
    #make the testing with these id's
34

    
35
    def setUp(self):
36
        self.client = Client()
37

    
38
    def test_api_version(self):
39
        """Check API version."""
40
        
41
        response = self.client.get('/api/v1.1/')
42
        self.assertEqual(response.status_code, 200)
43
        api_version = json.loads(response.content)['version']
44
        self.assertEqual(api_version['id'], 'v1.1')
45
        self.assertEqual(api_version['status'], 'CURRENT')
46

    
47
    def test_server_list(self):
48
        """Test if the expected list of servers is returned."""
49
        
50
        response = self.client.get('/api/v1.1/servers')
51
        vms_from_api = json.loads(response.content)['servers']['values']
52
        vms_from_db = VirtualMachine.objects.filter(deleted=False)
53
        self.assertEqual(len(vms_from_api), len(vms_from_db))
54
        self.assertTrue(response.status_code in [200, 203])
55
        for vm_from_api in vms_from_api:
56
            vm_from_db = VirtualMachine.objects.get(id=vm_from_api['id'])
57
            self.assertEqual(vm_from_api['id'], vm_from_db.id)
58
            self.assertEqual(vm_from_api['name'], vm_from_db.name)
59

    
60
    def test_server_details(self):
61
        """Test if the expected server is returned."""
62
        
63
        response = self.client.get('/api/v1.1/servers/%d' % self.test_server_id)
64
        vm_from_api = json.loads(response.content)['server']
65
        vm_from_db = VirtualMachine.objects.get(id=self.test_server_id)
66
        self.assertEqual(vm_from_api['flavorRef'], vm_from_db.flavor.id)
67
        self.assertEqual(vm_from_api['hostId'], vm_from_db.hostid)
68
        self.assertEqual(vm_from_api['id'], vm_from_db.id)
69
        self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id)
70
        self.assertEqual(vm_from_api['name'], vm_from_db.name)
71
        self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
72
        self.assertTrue(response.status_code in [200, 203])
73

    
74
    def test_servers_details(self):
75
        """Test if the servers details are returned."""
76
        
77
        response = self.client.get('/api/v1.1/servers/detail')
78

    
79
        # Make sure both DB and API responses are sorted by id,
80
        # to allow for 1-1 comparisons
81
        vms_from_db = VirtualMachine.objects.filter(deleted=False).order_by('id')
82
        vms_from_api = json.loads(response.content)['servers']['values']
83
        vms_from_api = sorted(vms_from_api, key=lambda vm: vm['id'])
84
        self.assertEqual(len(vms_from_db), len(vms_from_api))
85

    
86
        id_list = [vm.id for vm in vms_from_db]
87
        number = 0
88
        for vm_id in id_list:
89
            vm_from_api = vms_from_api[number]
90
            vm_from_db = VirtualMachine.objects.get(id=vm_id)
91
            self.assertEqual(vm_from_api['flavorRef'], vm_from_db.flavor.id)
92
            self.assertEqual(vm_from_api['hostId'], vm_from_db.hostid)
93
            self.assertEqual(vm_from_api['id'], vm_from_db.id)
94
            self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id)
95
            self.assertEqual(vm_from_api['name'], vm_from_db.name)
96
            self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
97
            number += 1
98
        for vm_from_api in vms_from_api:
99
            vm_from_db = VirtualMachine.objects.get(id=vm_from_api['id'])
100
            self.assertEqual(vm_from_api['flavorRef'], vm_from_db.flavor.id)
101
            self.assertEqual(vm_from_api['hostId'], vm_from_db.hostid)
102
            self.assertEqual(vm_from_api['id'], vm_from_db.id)
103
            self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id)
104
            self.assertEqual(vm_from_api['name'], vm_from_db.name)
105
            self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
106
        self.assertTrue(response.status_code in [200,203])
107

    
108
    def test_wrong_server(self):
109
        """Test 404 response if server does not exist."""
110
        
111
        response = self.client.get('/api/v1.1/servers/%d' % self.test_wrong_server_id)
112
        self.assertEqual(response.status_code, 404)
113

    
114
    def test_create_server_empty(self):
115
        """Test if the create server call returns a 400 badRequest if
116
           no attributes are specified."""
117
        
118
        response = self.client.post('/api/v1.1/servers', {})
119
        self.assertEqual(response.status_code, 400)
120

    
121
    def test_create_server(self):
122
        """Test if the create server call returns the expected response
123
           if a valid request has been speficied."""
124
        
125
        request = {
126
                    "server": {
127
                        "name": "new-server-test",
128
                        "imageRef": 1,
129
                        "flavorRef": 1,
130
                        "metadata": {
131
                            "My Server Name": "Apache1"
132
                        },
133
                        "personality": []
134
                    }
135
        }
136
        response = self.client.post('/api/v1.1/servers', json.dumps(request),
137
                                    content_type='application/json')
138
        self.assertEqual(response.status_code, 202)
139
        #TODO: check response.content
140
        #TODO: check create server with wrong options (eg non existing flavor)
141

    
142
    def test_server_polling(self):
143
        """Test if the server polling works as expected."""
144
        
145
        response = self.client.get('/api/v1.1/servers/detail')
146
        vms_from_api_initial = json.loads(response.content)['servers']['values']
147
        ts = mktime(parsedate(response['Date']))
148
        since = datetime.datetime.fromtimestamp(ts).isoformat() + 'Z'
149
        response = self.client.get('/api/v1.1/servers/detail?changes-since=%s' % since)
150
        self.assertEqual(len(response.content), 0)
151

    
152
        #now create a machine. Then check if it is on the list
153
        request = {
154
                    "server": {
155
                        "name": "new-server-test",
156
                        "imageRef": 1,
157
                        "flavorRef": 1,
158
                        "metadata": {
159
                            "My Server Name": "Apache1"
160
                        },
161
                        "personality": []
162
                    }
163
        }
164
        
165
        path = '/api/v1.1/servers'
166
        response = self.client.post(path, json.dumps(request), content_type='application/json')
167
        self.assertEqual(response.status_code, 202)
168

    
169
        response = self.client.get('/api/v1.1/servers/detail?changes-since=%s' % since)
170
        self.assertEqual(response.status_code, 200)
171
        vms_from_api_after = json.loads(response.content)['servers']['values']
172
        #make sure the newly created server is included on the updated list
173
        self.assertEqual(len(vms_from_api_after), 1)
174

    
175
    def test_reboot_server(self):
176
        """Test if the specified server is rebooted."""
177
        
178
        request = {'reboot': {'type': 'HARD'}}
179
        path = '/api/v1.1/servers/%d/action' % self.test_server_id
180
        response = self.client.post(path, json.dumps(request), content_type='application/json')
181
        self.assertEqual(response.status_code, 202)
182
        #server id that does not exist
183
        path = '/api/v1.1/servers/%d/action' % self.test_wrong_server_id
184
        response = self.client.post(path, json.dumps(request), content_type='application/json')
185
        self.assertEqual(response.status_code, 404)
186

    
187
    def test_shutdown_server(self):
188
        """Test if the specified server is shutdown."""
189
        
190
        request = {'shutdown': {}}
191
        path = '/api/v1.1/servers/%d/action' % self.test_server_id
192
        response = self.client.post(path, json.dumps(request), content_type='application/json')
193
        self.assertEqual(response.status_code, 202)
194
        #server id that does not exist
195
        path = '/api/v1.1/servers/%d/action' % self.test_wrong_server_id
196
        response = self.client.post(path, json.dumps(request), content_type='application/json')
197
        self.assertEqual(response.status_code, 404)
198

    
199
    def test_start_server(self):
200
        """Test if the specified server is started."""
201
        
202
        request = {'start': {}}
203
        path = '/api/v1.1/servers/%d/action' % self.test_server_id
204
        response = self.client.post(path, json.dumps(request), content_type='application/json')
205
        self.assertEqual(response.status_code, 202)
206
        #server id that does not exist
207
        path = '/api/v1.1/servers/%d/action' % self.test_wrong_server_id
208
        response = self.client.post(path, json.dumps(request), content_type='application/json')
209
        self.assertEqual(response.status_code, 404)
210

    
211
    def test_delete_server(self):
212
        """Test if the specified server is deleted."""
213
        response = self.client.delete('/api/v1.1/servers/%d' % self.test_server_id)
214
        self.assertEqual(response.status_code, 204)
215
        #server id that does not exist
216
        response = self.client.delete('/api/v1.1/servers/%d' % self.test_wrong_server_id)
217
        self.assertEqual(response.status_code, 404)
218

    
219
    def test_flavor_list(self):
220
        """Test if the expected list of flavors is returned by."""
221
        
222
        response = self.client.get('/api/v1.1/flavors')
223
        flavors_from_api = json.loads(response.content)['flavors']['values']
224
        flavors_from_db = Flavor.objects.all()
225
        self.assertEqual(len(flavors_from_api), len(flavors_from_db))
226
        self.assertTrue(response.status_code in [200, 203])
227
        for flavor_from_api in flavors_from_api:
228
            flavor_from_db = Flavor.objects.get(id=flavor_from_api['id'])
229
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
230
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
231

    
232
    def test_flavors_details(self):
233
        """Test if the flavors details are returned."""
234
        
235
        response = self.client.get('/api/v1.1/flavors/detail')
236
        flavors_from_db = Flavor.objects.all()
237
        flavors_from_api = json.loads(response.content)['flavors']['values']
238

    
239
        # Assert that all flavors in the db appear inthe API call result
240
        for i in range(0, len(flavors_from_db)):
241
            flavor_from_api = flavors_from_api[i]
242
            flavor_from_db = Flavor.objects.get(id=flavors_from_db[i].id)
243
            self.assertEqual(flavor_from_api['cpu'], flavor_from_db.cpu)
244
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
245
            self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
246
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
247
            self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
248

    
249
        # Assert that all flavors returned by the API also exist in the db
250
        for flavor_from_api in flavors_from_api:
251
            flavor_from_db = Flavor.objects.get(id=flavor_from_api['id'])
252
            self.assertEqual(flavor_from_api['cpu'], flavor_from_db.cpu)
253
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
254
            self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
255
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
256
            self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
257

    
258
        # Check if we have the right status_code
259
        self.assertTrue(response.status_code in [200, 203])
260

    
261
    def test_flavor_details(self):
262
        """Test if the expected flavor is returned."""
263
        
264
        response = self.client.get('/api/v1.1/flavors/%d' % self.test_flavor_id)
265
        flavor_from_api = json.loads(response.content)['flavor']
266
        flavor_from_db = Flavor.objects.get(id=self.test_flavor_id)
267
        self.assertEqual(flavor_from_api['cpu'], flavor_from_db.cpu)
268
        self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
269
        self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
270
        self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
271
        self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
272
        self.assertTrue(response.status_code in [200, 203])
273

    
274
    def test_wrong_flavor(self):
275
        """Test 404 result when requesting a flavor that does not exist."""
276
        
277
        response = self.client.get('/api/v1.1/flavors/%d' % self.test_wrong_flavor_id)
278
        self.assertTrue(response.status_code in [404, 503])
279

    
280
    def test_image_list(self):
281
        """Test if the expected list of images is returned by the API."""
282
        
283
        response = self.client.get('/api/v1.1/images')
284
        images_from_api = json.loads(response.content)['images']['values']
285
        images_from_db = Image.objects.all()
286
        self.assertEqual(len(images_from_api), len(images_from_db))
287
        self.assertTrue(response.status_code in [200, 203])
288
        for image_from_api in images_from_api:
289
            image_from_db = Image.objects.get(id=image_from_api['id'])
290
            self.assertEqual(image_from_api['id'], image_from_db.id)
291
            self.assertEqual(image_from_api['name'], image_from_db.name)
292

    
293
    def test_image_details(self):
294
        """Test if the expected image is returned."""
295
        
296
        response = self.client.get('/api/v1.1/images/%d' % self.test_image_id)
297
        image_from_api = json.loads(response.content)['image']
298
        image_from_db = Image.objects.get(id=self.test_image_id)
299
        self.assertEqual(image_from_api['name'], image_from_db.name)
300
        self.assertEqual(image_from_api['id'], image_from_db.id)
301
        self.assertEqual(image_from_api.get('serverRef', ''),
302
                        image_from_db.sourcevm and image_from_db.sourcevm.id or '')
303
        self.assertEqual(image_from_api['status'], image_from_db.state)
304
        self.assertTrue(response.status_code in [200, 203])
305

    
306
    def test_images_details(self):
307
        """Test if the images details are returned."""
308
        
309
        response = self.client.get('/api/v1.1/images/detail')
310
        images_from_api = json.loads(response.content)['images']['values']
311
        images_from_db = Image.objects.all()
312
        for i in range(0, len(images_from_db)):
313
            image_from_db = Image.objects.get(id=images_from_db[i].id)
314
            image_from_api = images_from_api[i]
315
            self.assertEqual(image_from_api['name'], image_from_db.name)
316
            self.assertEqual(image_from_api['id'], image_from_db.id)
317
            self.assertEqual(image_from_api.get('serverRef', ''),
318
                             image_from_db.sourcevm and
319
                             image_from_db.sourcevm.id or "")
320
            self.assertEqual(image_from_api['status'], image_from_db.state)
321

    
322
        for image_from_api in images_from_api:
323
            image_from_db = Image.objects.get(id=image_from_api['id'])
324
            self.assertEqual(image_from_api['name'], image_from_db.name)
325
            self.assertEqual(image_from_api['id'], image_from_db.id)
326
            self.assertEqual(image_from_api.get('serverRef', ''),
327
                             image_from_db.sourcevm and
328
                             image_from_db.sourcevm.id or "")
329
            self.assertEqual(image_from_api['status'], image_from_db.state)
330

    
331
        self.assertTrue(response.status_code in [200, 203])
332

    
333
    def test_wrong_image(self):
334
        """Test 404 result if a non existent image is requested."""
335
        
336
        response = self.client.get('/api/v1.1/images/%d' % self.test_wrong_image_id)
337
        self.assertEqual(response.status_code, 404)
338

    
339
    def test_server_metadata(self):
340
        """Test server's metadata (add, edit)."""
341
        
342
        key = 'name'
343
        request = {'meta': {key: 'a fancy name'}}
344
        
345
        path = '/api/v1.1/servers/%d/meta/%s' % (self.test_server_id, key)
346
        response = self.client.put(path, json.dumps(request), content_type='application/json')
347
        self.assertEqual(response.status_code, 201)
348

    
349

    
350
def create_users(n=1):
351
    for i in range(n):
352
        SynnefoUser.objects.create(
353
            name='User %d' % i,
354
            credit=0)
355

    
356
def create_flavors(n=1):
357
    for i in range(n):
358
        Flavor.objects.create(
359
            cpu=randint(1, 4),
360
            ram=randint(1, 8) * 512,
361
            disk=randint(1, 40))
362

    
363
def create_images(n=1):
364
    users = SynnefoUser.objects.all()
365
    for i in range(n):
366
        Image.objects.create(
367
            name='Image %d' % (i + 1),
368
            state='ACTIVE',
369
            owner=choice(users))
370

    
371
def create_image_metadata(n=1):
372
    images = Image.objects.all()
373
    for i in range(n):
374
        ImageMetadata.objects.create(
375
            meta_key='Key%d' % (i + 1),
376
            meta_value='Value %d' % (i + 1),
377
            image = choice(images))
378

    
379
def create_servers(n=1):
380
    users = SynnefoUser.objects.all()
381
    flavors = Flavor.objects.all()
382
    images = Image.objects.all()
383
    for i in range(n):
384
        VirtualMachine.objects.create(
385
            name='Server %d' % (i + 1),
386
            owner=choice(users),
387
            sourceimage=choice(images),
388
            hostid=str(i),
389
            ipfour='0.0.0.0',
390
            ipsix='::1',
391
            flavor=choice(flavors))
392

    
393
def create_server_metadata(n=1):
394
    servers = VirtualMachine.objects.all()
395
    for i in range(n):
396
        VirtualMachineMetadata.objects.create(
397
            meta_key='Key%d' % (i + 1),
398
            meta_value='Value %d' % (i + 1),
399
            vm = choice(servers))
400

    
401

    
402
class AssertInvariant(object):
403
    def __init__(self, callable, *args, **kwargs):
404
        self.callable = callable
405
        self.args = args
406
        self.kwargs = kwargs
407
    
408
    def __enter__(self):
409
        self.value = self.callable(*self.args, **self.kwargs)
410
        return self.value
411
    
412
    def __exit__(self, type, value, tb):
413
        assert self.value == self.callable(*self.args, **self.kwargs)
414

    
415

    
416
class BaseTestCase(TestCase):
417
    USERS = 1
418
    FLAVORS = 1
419
    IMAGES = 1
420
    SERVERS = 1
421
    SERVER_METADATA = 0
422
    IMAGE_METADATA = 0
423
    
424
    def setUp(self):
425
        self.client = Client()
426
        create_users(self.USERS)
427
        create_flavors(self.FLAVORS)
428
        create_images(self.IMAGES)
429
        create_image_metadata(self.IMAGE_METADATA)
430
        create_servers(self.SERVERS)
431
        create_server_metadata(self.SERVER_METADATA)
432
    
433
    def assertFault(self, response, status_code, name):
434
        self.assertEqual(response.status_code, status_code)
435
        fault = json.loads(response.content)
436
        self.assertEqual(fault.keys(), [name])
437
    
438
    def assertBadRequest(self, response):
439
        self.assertFault(response, 400, 'badRequest')
440

    
441
    def assertItemNotFound(self, response):
442
        self.assertFault(response, 404, 'itemNotFound')
443
    
444
    
445
    def list_metadata(self, path):
446
        response = self.client.get(path)
447
        self.assertTrue(response.status_code in (200, 203))
448
        reply = json.loads(response.content)
449
        self.assertEqual(reply.keys(), ['metadata'])
450
        self.assertEqual(reply['metadata'].keys(), ['values'])
451
        return reply['metadata']['values']
452
    
453
    def list_server_metadata(self, server_id):
454
        path = '/api/v1.1/servers/%d/meta' % server_id
455
        return self.list_metadata(path)
456
    
457
    def list_image_metadata(self, image_id):
458
        path = '/api/v1.1/images/%d/meta' % image_id
459
        return self.list_metadata(path)
460
    
461
    def update_metadata(self, path, metadata):
462
        data = json.dumps({'metadata': metadata})
463
        response = self.client.post(path, data, content_type='application/json')
464
        self.assertEqual(response.status_code, 201)
465
        reply = json.loads(response.content)
466
        self.assertEqual(reply.keys(), ['metadata'])
467
        return reply['metadata']
468
    
469
    def update_server_metadata(self, server_id, metadata):
470
        path = '/api/v1.1/servers/%d/meta' % server_id
471
        return self.update_metadata(path, metadata)
472
    
473
    def update_image_metadata(self, image_id, metadata):
474
        path = '/api/v1.1/images/%d/meta' % image_id
475
        return self.update_metadata(path, metadata)
476
    
477
    def create_server_meta(self, server_id, meta):
478
        key = meta.keys()[0]
479
        path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
480
        data = json.dumps({'meta': meta})
481
        response = self.client.put(path, data, content_type='application/json')
482
        self.assertEqual(response.status_code, 201)
483
        reply = json.loads(response.content)
484
        self.assertEqual(reply.keys(), ['meta'])
485
        response_meta = reply['meta']
486
        self.assertEqual(response_meta, meta)
487
    
488
    def get_all_server_metadata(self):
489
        metadata = defaultdict(dict)
490
        for m in VirtualMachineMetadata.objects.all():
491
            metadata[m.vm.id][m.meta_key] = m.meta_value
492
        return metadata
493
    
494
    def get_all_image_metadata(self):
495
        metadata = defaultdict(dict)
496
        for m in ImageMetadata.objects.all():
497
            metadata[m.image.id][m.meta_key] = m.meta_value
498
        return metadata
499

    
500

    
501
class ListServerMetadata(BaseTestCase):
502
    SERVERS = 5
503
    SERVER_METADATA = 100
504
    
505
    def test_list_metadata(self):
506
        with AssertInvariant(self.get_all_server_metadata) as metadata:
507
            for vm in VirtualMachine.objects.all():
508
                response_metadata = self.list_server_metadata(vm.id)
509
                self.assertEqual(response_metadata, metadata[vm.id])
510
    
511
    def test_invalid_server(self):
512
        with AssertInvariant(self.get_all_server_metadata):
513
            response = self.client.get('/api/v1.1/servers/0/meta')
514
            self.assertItemNotFound(response)
515

    
516

    
517
class UpdateServerMetadata(BaseTestCase):
518
    SERVER_METADATA = 10
519
    
520
    def test_update_metadata(self):
521
        metadata = self.get_all_server_metadata()
522
        server_id = choice(metadata.keys())
523
        new_metadata = {}
524
        for key in sample(metadata[server_id].keys(), 3):
525
            new_metadata[key] = 'New %s value' % key
526
        response_metadata = self.update_server_metadata(server_id, new_metadata)
527
        self.assertEqual(response_metadata, new_metadata)
528
        metadata[server_id].update(new_metadata)
529
        self.assertEqual(metadata, self.get_all_server_metadata())
530
    
531
    def test_does_not_create(self):
532
        with AssertInvariant(self.get_all_server_metadata) as metadata:
533
            server_id = choice(metadata.keys())
534
            new_metadata = {'Foo': 'Bar'}
535
            response_metadata = self.update_server_metadata(server_id, new_metadata)
536
            self.assertEqual(response_metadata, {})
537
    
538
    def test_invalid_data(self):
539
        with AssertInvariant(self.get_all_server_metadata) as metadata:
540
            server_id = choice(metadata.keys())
541
            path = '/api/v1.1/servers/%d/meta' % server_id
542
            response = self.client.post(path, 'metadata', content_type='application/json')
543
            self.assertBadRequest(response)
544
    
545
    def test_invalid_server(self):
546
        with AssertInvariant(self.get_all_server_metadata):
547
            path = '/api/v1.1/servers/0/meta'
548
            data = json.dumps({'metadata': {'Key1': 'A Value'}})
549
            response = self.client.post(path, data, content_type='application/json')
550
            self.assertItemNotFound(response)
551

    
552

    
553
class GetServerMetadataItem(BaseTestCase):
554
    SERVERS = 5
555
    SERVER_METADATA = 100
556
    
557
    def test_get_metadata_item(self):
558
        with AssertInvariant(self.get_all_server_metadata) as metadata:
559
            server_id = choice(metadata.keys())
560
            key = choice(metadata[server_id].keys())
561
            path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
562
            response = self.client.get(path)
563
            self.assertTrue(response.status_code in (200, 203))
564
            reply = json.loads(response.content)
565
            self.assertEqual(reply['meta'], {key: metadata[server_id][key]})
566
    
567
    def test_invalid_key(self):
568
        with AssertInvariant(self.get_all_server_metadata) as metadata:
569
            server_id = choice(metadata.keys())
570
            response = self.client.get('/api/v1.1/servers/%d/meta/foo' % server_id)
571
            self.assertItemNotFound(response)
572
    
573
    def test_invalid_server(self):
574
        with AssertInvariant(self.get_all_server_metadata):
575
            response = self.client.get('/api/v1.1/servers/0/meta/foo')
576
            self.assertItemNotFound(response)
577

    
578

    
579
class CreateServerMetadataItem(BaseTestCase):
580
    SERVER_METADATA = 10
581
    
582
    def test_create_metadata(self):
583
        metadata = self.get_all_server_metadata()
584
        server_id = choice(metadata.keys())
585
        meta = {'Foo': 'Bar'}
586
        self.create_server_meta(server_id, meta)
587
        metadata[server_id].update(meta)
588
        self.assertEqual(metadata, self.get_all_server_metadata())
589
    
590
    def test_update_metadata(self):
591
        metadata = self.get_all_server_metadata()
592
        server_id = choice(metadata.keys())
593
        key = choice(metadata[server_id].keys())
594
        meta = {key: 'New Value'}
595
        self.create_server_meta(server_id, meta)
596
        metadata[server_id].update(meta)
597
        self.assertEqual(metadata, self.get_all_server_metadata())
598
    
599
    def test_invalid_server(self):
600
        with AssertInvariant(self.get_all_server_metadata):
601
            path = '/api/v1.1/servers/0/meta/foo'
602
            data = json.dumps({'meta': {'foo': 'bar'}})
603
            response = self.client.put(path, data, content_type='application/json')
604
            self.assertItemNotFound(response)
605
    
606
    def test_invalid_key(self):
607
        with AssertInvariant(self.get_all_server_metadata) as metadata:
608
            server_id = choice(metadata.keys())
609
            path = '/api/v1.1/servers/%d/meta/baz' % server_id
610
            data = json.dumps({'meta': {'foo': 'bar'}})
611
            response = self.client.put(path, data, content_type='application/json')
612
            self.assertBadRequest(response)
613
    
614
    def test_invalid_data(self):
615
        with AssertInvariant(self.get_all_server_metadata) as metadata:
616
            server_id = choice(metadata.keys())
617
            path = '/api/v1.1/servers/%d/meta/foo' % server_id
618
            response = self.client.put(path, 'meta', content_type='application/json')
619
            self.assertBadRequest(response)
620

    
621

    
622
class DeleteServerMetadataItem(BaseTestCase):
623
    SERVER_METADATA = 10
624
    
625
    def test_delete_metadata(self):
626
        metadata = self.get_all_server_metadata()
627
        server_id = choice(metadata.keys())
628
        key = choice(metadata[server_id].keys())
629
        path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
630
        response = self.client.delete(path)
631
        self.assertEqual(response.status_code, 204)
632
        metadata[server_id].pop(key)
633
        self.assertEqual(metadata, self.get_all_server_metadata())
634
    
635
    def test_invalid_server(self):
636
        with AssertInvariant(self.get_all_server_metadata):
637
            response = self.client.delete('/api/v1.1/servers/9/meta/Key1')
638
            self.assertItemNotFound(response)
639
    
640
    def test_invalid_key(self):
641
        with AssertInvariant(self.get_all_server_metadata) as metadata:
642
            server_id = choice(metadata.keys())
643
            path = '/api/v1.1/servers/%d/meta/foo' % server_id
644
            response = self.client.delete(path)
645
            self.assertItemNotFound(response)
646

    
647

    
648
class ListImageMetadata(BaseTestCase):
649
    IMAGES = 5
650
    IMAGE_METADATA = 100
651

    
652
    def test_list_metadata(self):
653
        with AssertInvariant(self.get_all_image_metadata) as metadata:
654
            for image in Image.objects.all():
655
                response_metadata = self.list_image_metadata(image.id)
656
                self.assertEqual(response_metadata, metadata[image.id])
657

    
658
    def test_invalid_image(self):
659
        with AssertInvariant(self.get_all_image_metadata):
660
            response = self.client.get('/api/v1.1/images/0/meta')
661
            self.assertItemNotFound(response)
662

    
663
class UpdateImageMetadata(BaseTestCase):
664
    IMAGE_METADATA = 10
665

    
666
    def test_update_metadata(self):
667
        metadata = self.get_all_image_metadata()
668
        image_id = choice(metadata.keys())
669
        new_metadata = {}
670
        for key in sample(metadata[image_id].keys(), 3):
671
            new_metadata[key] = 'New %s value' % key
672
        response_metadata = self.update_image_metadata(image_id, new_metadata)
673
        self.assertEqual(response_metadata, new_metadata)
674
        metadata[image_id].update(new_metadata)
675
        self.assertEqual(metadata, self.get_all_image_metadata())
676

    
677
    def test_does_not_create(self):
678
        with AssertInvariant(self.get_all_image_metadata) as metadata:
679
            image_id = choice(metadata.keys())
680
            new_metadata = {'Foo': 'Bar'}
681
            response_metadata = self.update_image_metadata(image_id, new_metadata)
682
            self.assertEqual(response_metadata, {})
683

    
684
    def test_invalid_data(self):
685
        with AssertInvariant(self.get_all_image_metadata) as metadata:
686
            image_id = choice(metadata.keys())
687
            path = '/api/v1.1/images/%d/meta' % image_id
688
            response = self.client.post(path, 'metadata', content_type='application/json')
689
            self.assertBadRequest(response)
690

    
691
    def test_invalid_server(self):
692
        with AssertInvariant(self.get_all_image_metadata):
693
            path = '/api/v1.1/images/0/meta'
694
            data = json.dumps({'metadata': {'Key1': 'A Value'}})
695
            response = self.client.post(path, data, content_type='application/json')
696
            self.assertItemNotFound(response)
697

    
698

    
699
class ServerVNCConsole(BaseTestCase):
700
    SERVERS = 1
701

    
702
    def test_not_active_server(self):
703
        """Test console req for server not in ACTIVE state returns badRequest"""
704
        server_id = choice(VirtualMachine.objects.all()).id
705
        path = '/api/v1.1/servers/%d/action' % server_id
706
        data = json.dumps({'console': {'type': 'vnc'}})
707
        response = self.client.post(path, data, content_type='application/json')
708
        self.assertBadRequest(response)
709

    
710
    def test_active_server(self):
711
        """Test console req for ACTIVE server"""
712
        server_id = choice(VirtualMachine.objects.all()).id
713
        # FIXME: Start the server properly, instead of tampering with the DB
714
        vm = choice(VirtualMachine.objects.all())
715
        vm.operstate = 'STARTED'
716
        vm.save()
717
        server_id = vm.id
718
        
719
        path = '/api/v1.1/servers/%d/action' % server_id
720
        data = json.dumps({'console': {'type': 'vnc'}})
721
        response = self.client.post(path, data, content_type='application/json')
722
        self.assertEqual(response.status_code, 200)
723
        reply = json.loads(response.content)
724
        self.assertEqual(reply.keys(), ['console'])
725
        console = reply['console']
726
        self.assertEqual(console['type'], 'vnc')
727
        self.assertEqual(set(console.keys()), set(['type', 'host', 'port', 'password']))