Statistics
| Branch: | Tag: | Revision:

root / api / tests.py @ 40777cc8

History | View | Annotate | Download (30.6 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.db.models import *
19
from synnefo.logic.utils import get_rsapi_state
20

    
21

    
22
class AaiClient(Client):
23
    def request(self, **request):
24
        request['HTTP_X_AUTH_TOKEN'] = '46e427d657b20defe352804f0eb6f8a2'
25
        return super(AaiClient, self).request(**request)
26

    
27

    
28
class APITestCase(TestCase):
29
    fixtures = ['api_test_data']
30
    test_server_id = 1001
31
    test_image_id = 1
32
    test_flavor_id = 1
33
    test_group_id = 1
34
    test_wrong_server_id = 99999999
35
    test_wrong_image_id = 99999999
36
    test_wrong_flavor_id = 99999999
37
    test_wrong_group_id = 99999999
38
    #make the testing with these id's
39

    
40
    def setUp(self):
41
        self.client = AaiClient()
42

    
43
    def test_api_version(self):
44
        """Check API version."""
45
        
46
        response = self.client.get('/api/v1.1/')
47
        self.assertEqual(response.status_code, 200)
48
        api_version = json.loads(response.content)['version']
49
        self.assertEqual(api_version['id'], 'v1.1')
50
        self.assertEqual(api_version['status'], 'CURRENT')
51

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

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

    
79
    def test_servers_details(self):
80
        """Test if the servers details are returned."""
81
        
82
        response = self.client.get('/api/v1.1/servers/detail')
83

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

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

    
113
    def test_wrong_server(self):
114
        """Test 404 response if server does not exist."""
115
        
116
        response = self.client.get('/api/v1.1/servers/%d' % self.test_wrong_server_id)
117
        self.assertEqual(response.status_code, 404)
118

    
119
    def test_create_server_empty(self):
120
        """Test if the create server call returns a 400 badRequest if
121
           no attributes are specified."""
122
        
123
        response = self.client.post('/api/v1.1/servers', {})
124
        self.assertEqual(response.status_code, 400)
125

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

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

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

    
175
        response = self.client.get('/api/v1.1/servers/detail?changes-since=%s' % since)
176
        self.assertEqual(response.status_code, 200)
177
        vms_from_api_after = json.loads(response.content)['servers']['values']
178
        #make sure the newly created server is included on the updated list
179
        self.assertEqual(len(vms_from_api_after), 1)
180

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

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

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

    
217
    def test_delete_server(self):
218
        """Test if the specified server is deleted."""
219
        response = self.client.delete('/api/v1.1/servers/%d' % self.test_server_id)
220
        self.assertEqual(response.status_code, 204)
221
        #server id that does not exist
222
        response = self.client.delete('/api/v1.1/servers/%d' % self.test_wrong_server_id)
223
        self.assertEqual(response.status_code, 404)
224

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

    
238
    def test_flavors_details(self):
239
        """Test if the flavors details are returned."""
240
        
241
        response = self.client.get('/api/v1.1/flavors/detail')
242
        flavors_from_db = Flavor.objects.all()
243
        flavors_from_api = json.loads(response.content)['flavors']['values']
244

    
245
        # Assert that all flavors in the db appear inthe API call result
246
        for i in range(0, len(flavors_from_db)):
247
            flavor_from_api = flavors_from_api[i]
248
            flavor_from_db = Flavor.objects.get(id=flavors_from_db[i].id)
249
            self.assertEqual(flavor_from_api['cpu'], flavor_from_db.cpu)
250
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
251
            self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
252
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
253
            self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
254

    
255
        # Assert that all flavors returned by the API also exist in the db
256
        for flavor_from_api in flavors_from_api:
257
            flavor_from_db = Flavor.objects.get(id=flavor_from_api['id'])
258
            self.assertEqual(flavor_from_api['cpu'], flavor_from_db.cpu)
259
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
260
            self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
261
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
262
            self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
263

    
264
        # Check if we have the right status_code
265
        self.assertTrue(response.status_code in [200, 203])
266

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

    
280
    def test_wrong_flavor(self):
281
        """Test 404 result when requesting a flavor that does not exist."""
282
        
283
        response = self.client.get('/api/v1.1/flavors/%d' % self.test_wrong_flavor_id)
284
        self.assertTrue(response.status_code in [404, 503])
285

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

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

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

    
328
        for image_from_api in images_from_api:
329
            image_from_db = Image.objects.get(id=image_from_api['id'])
330
            self.assertEqual(image_from_api['name'], image_from_db.name)
331
            self.assertEqual(image_from_api['id'], image_from_db.id)
332
            self.assertEqual(image_from_api.get('serverRef', ''),
333
                             image_from_db.sourcevm and
334
                             image_from_db.sourcevm.id or "")
335
            self.assertEqual(image_from_api['status'], image_from_db.state)
336

    
337
        self.assertTrue(response.status_code in [200, 203])
338

    
339
    def test_wrong_image(self):
340
        """Test 404 result if a non existent image is requested."""
341
        
342
        response = self.client.get('/api/v1.1/images/%d' % self.test_wrong_image_id)
343
        self.assertEqual(response.status_code, 404)
344

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

    
355

    
356
def create_users(n=1):
357
    for i in range(n):
358
        SynnefoUser.objects.create(
359
            name='User %d' % i,
360
            credit=0)
361

    
362
def create_flavors(n=1):
363
    for i in range(n):
364
        Flavor.objects.create(
365
            cpu=randint(1, 4),
366
            ram=randint(1, 8) * 512,
367
            disk=randint(1, 40))
368

    
369
def create_images(n=1):
370
    users = SynnefoUser.objects.all()
371
    for i in range(n):
372
        Image.objects.create(
373
            name='Image %d' % (i + 1),
374
            state='ACTIVE',
375
            owner=choice(users))
376

    
377
def create_image_metadata(n=1):
378
    images = Image.objects.all()
379
    for i in range(n):
380
        ImageMetadata.objects.create(
381
            meta_key='Key%d' % (i + 1),
382
            meta_value='Value %d' % (i + 1),
383
            image = choice(images))
384

    
385
def create_servers(n=1):
386
    users = SynnefoUser.objects.all()
387
    flavors = Flavor.objects.all()
388
    images = Image.objects.all()
389
    for i in range(n):
390
        VirtualMachine.objects.create(
391
            name='Server %d' % (i + 1),
392
            owner=choice(users),
393
            sourceimage=choice(images),
394
            hostid=str(i),
395
            ipfour='0.0.0.0',
396
            ipsix='::1',
397
            flavor=choice(flavors))
398

    
399
def create_server_metadata(n=1):
400
    servers = VirtualMachine.objects.all()
401
    for i in range(n):
402
        VirtualMachineMetadata.objects.create(
403
            meta_key='Key%d' % (i + 1),
404
            meta_value='Value %d' % (i + 1),
405
            vm = choice(servers))
406

    
407

    
408
class AssertInvariant(object):
409
    def __init__(self, callable, *args, **kwargs):
410
        self.callable = callable
411
        self.args = args
412
        self.kwargs = kwargs
413
    
414
    def __enter__(self):
415
        self.value = self.callable(*self.args, **self.kwargs)
416
        return self.value
417
    
418
    def __exit__(self, type, value, tb):
419
        assert self.value == self.callable(*self.args, **self.kwargs)
420

    
421

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

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

    
506

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

    
522

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

    
558

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

    
584

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

    
627

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

    
653

    
654
class ListImageMetadata(BaseTestCase):
655
    IMAGES = 5
656
    IMAGE_METADATA = 100
657

    
658
    def test_list_metadata(self):
659
        with AssertInvariant(self.get_all_image_metadata) as metadata:
660
            for image in Image.objects.all():
661
                response_metadata = self.list_image_metadata(image.id)
662
                self.assertEqual(response_metadata, metadata[image.id])
663

    
664
    def test_invalid_image(self):
665
        with AssertInvariant(self.get_all_image_metadata):
666
            response = self.client.get('/api/v1.1/images/0/meta')
667
            self.assertItemNotFound(response)
668

    
669
class UpdateImageMetadata(BaseTestCase):
670
    IMAGE_METADATA = 10
671

    
672
    def test_update_metadata(self):
673
        metadata = self.get_all_image_metadata()
674
        image_id = choice(metadata.keys())
675
        new_metadata = {}
676
        for key in sample(metadata[image_id].keys(), 3):
677
            new_metadata[key] = 'New %s value' % key
678
        response_metadata = self.update_image_metadata(image_id, new_metadata)
679
        self.assertEqual(response_metadata, new_metadata)
680
        metadata[image_id].update(new_metadata)
681
        self.assertEqual(metadata, self.get_all_image_metadata())
682

    
683
    def test_does_not_create(self):
684
        with AssertInvariant(self.get_all_image_metadata) as metadata:
685
            image_id = choice(metadata.keys())
686
            new_metadata = {'Foo': 'Bar'}
687
            response_metadata = self.update_image_metadata(image_id, new_metadata)
688
            self.assertEqual(response_metadata, {})
689

    
690
    def test_invalid_data(self):
691
        with AssertInvariant(self.get_all_image_metadata) as metadata:
692
            image_id = choice(metadata.keys())
693
            path = '/api/v1.1/images/%d/meta' % image_id
694
            response = self.client.post(path, 'metadata', content_type='application/json')
695
            self.assertBadRequest(response)
696

    
697
    def test_invalid_server(self):
698
        with AssertInvariant(self.get_all_image_metadata):
699
            path = '/api/v1.1/images/0/meta'
700
            data = json.dumps({'metadata': {'Key1': 'A Value'}})
701
            response = self.client.post(path, data, content_type='application/json')
702
            self.assertItemNotFound(response)
703

    
704

    
705
class ServerVNCConsole(BaseTestCase):
706
    SERVERS = 1
707

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

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