root / api / tests.py @ 13b954b0
History | View | Annotate | Download (36.5 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_wrong_image(self): |
300 |
"""Test 404 result if a non existent image is requested."""
|
301 |
|
302 |
response = self.client.get('/api/v1.1/images/%d' % self.test_wrong_image_id) |
303 |
self.assertEqual(response.status_code, 404) |
304 |
|
305 |
def test_server_metadata(self): |
306 |
"""Test server's metadata (add, edit)."""
|
307 |
|
308 |
key = 'name'
|
309 |
request = {'meta': {key: 'a fancy name'}} |
310 |
|
311 |
path = '/api/v1.1/servers/%d/meta/%s' % (self.test_server_id, key) |
312 |
response = self.client.put(path, json.dumps(request), content_type='application/json') |
313 |
self.assertEqual(response.status_code, 201) |
314 |
|
315 |
|
316 |
def create_users(n=1): |
317 |
for i in range(n): |
318 |
SynnefoUser.objects.create( |
319 |
name='User %d' % i,
|
320 |
credit=0)
|
321 |
|
322 |
def create_flavors(n=1): |
323 |
for i in range(n): |
324 |
Flavor.objects.create( |
325 |
cpu=randint(1, 4), |
326 |
ram=randint(1, 8) * 512, |
327 |
disk=randint(1, 40)) |
328 |
|
329 |
def create_images(n=1): |
330 |
users = SynnefoUser.objects.all() |
331 |
for i in range(n): |
332 |
Image.objects.create( |
333 |
name='Image %d' % (i + 1), |
334 |
state='ACTIVE',
|
335 |
owner=choice(users)) |
336 |
|
337 |
def create_image_metadata(n=1): |
338 |
images = Image.objects.all() |
339 |
for i in range(n): |
340 |
ImageMetadata.objects.create( |
341 |
meta_key='Key%d' % (i + 1), |
342 |
meta_value='Value %d' % (i + 1), |
343 |
image = choice(images)) |
344 |
|
345 |
def create_servers(n=1): |
346 |
users = SynnefoUser.objects.all() |
347 |
flavors = Flavor.objects.all() |
348 |
images = Image.objects.all() |
349 |
for i in range(n): |
350 |
VirtualMachine.objects.create( |
351 |
name='Server %d' % (i + 1), |
352 |
owner=choice(users), |
353 |
sourceimage=choice(images), |
354 |
hostid=str(i),
|
355 |
ipfour='0.0.0.0',
|
356 |
ipsix='::1',
|
357 |
flavor=choice(flavors)) |
358 |
|
359 |
def create_server_metadata(n=1): |
360 |
servers = VirtualMachine.objects.all() |
361 |
for i in range(n): |
362 |
VirtualMachineMetadata.objects.create( |
363 |
meta_key='Key%d' % (i + 1), |
364 |
meta_value='Value %d' % (i + 1), |
365 |
vm = choice(servers)) |
366 |
|
367 |
def create_networks(n): |
368 |
users = SynnefoUser.objects.all() |
369 |
for i in range(n): |
370 |
Network.objects.create( |
371 |
name='Network%d' % (i + 1), |
372 |
owner=choice(users)) |
373 |
|
374 |
|
375 |
class AssertInvariant(object): |
376 |
def __init__(self, callable, *args, **kwargs): |
377 |
self.callable = callable |
378 |
self.args = args
|
379 |
self.kwargs = kwargs
|
380 |
|
381 |
def __enter__(self): |
382 |
self.value = self.callable(*self.args, **self.kwargs) |
383 |
return self.value |
384 |
|
385 |
def __exit__(self, type, value, tb): |
386 |
assert self.value == self.callable(*self.args, **self.kwargs) |
387 |
|
388 |
|
389 |
class BaseTestCase(TestCase): |
390 |
USERS = 0
|
391 |
FLAVORS = 1
|
392 |
IMAGES = 1
|
393 |
SERVERS = 1
|
394 |
SERVER_METADATA = 0
|
395 |
IMAGE_METADATA = 0
|
396 |
NETWORKS = 0
|
397 |
|
398 |
def setUp(self): |
399 |
self.client = AaiClient()
|
400 |
create_users(self.USERS)
|
401 |
create_flavors(self.FLAVORS)
|
402 |
create_images(self.IMAGES)
|
403 |
create_image_metadata(self.IMAGE_METADATA)
|
404 |
create_servers(self.SERVERS)
|
405 |
create_server_metadata(self.SERVER_METADATA)
|
406 |
create_networks(self.NETWORKS)
|
407 |
|
408 |
def assertFault(self, response, status_code, name): |
409 |
self.assertEqual(response.status_code, status_code)
|
410 |
fault = json.loads(response.content) |
411 |
self.assertEqual(fault.keys(), [name])
|
412 |
|
413 |
def assertBadRequest(self, response): |
414 |
self.assertFault(response, 400, 'badRequest') |
415 |
|
416 |
def assertItemNotFound(self, response): |
417 |
self.assertFault(response, 404, 'itemNotFound') |
418 |
|
419 |
|
420 |
def list_images(self, detail=False): |
421 |
path = '/api/v1.1/images'
|
422 |
if detail:
|
423 |
path += '/detail'
|
424 |
response = self.client.get(path)
|
425 |
self.assertTrue(response.status_code in (200, 203)) |
426 |
reply = json.loads(response.content) |
427 |
self.assertEqual(reply.keys(), ['images']) |
428 |
self.assertEqual(reply['images'].keys(), ['values']) |
429 |
return reply['images']['values'] |
430 |
|
431 |
def list_metadata(self, path): |
432 |
response = self.client.get(path)
|
433 |
self.assertTrue(response.status_code in (200, 203)) |
434 |
reply = json.loads(response.content) |
435 |
self.assertEqual(reply.keys(), ['metadata']) |
436 |
self.assertEqual(reply['metadata'].keys(), ['values']) |
437 |
return reply['metadata']['values'] |
438 |
|
439 |
def list_server_metadata(self, server_id): |
440 |
path = '/api/v1.1/servers/%d/meta' % server_id
|
441 |
return self.list_metadata(path) |
442 |
|
443 |
def list_image_metadata(self, image_id): |
444 |
path = '/api/v1.1/images/%d/meta' % image_id
|
445 |
return self.list_metadata(path) |
446 |
|
447 |
def update_metadata(self, path, metadata): |
448 |
data = json.dumps({'metadata': metadata})
|
449 |
response = self.client.post(path, data, content_type='application/json') |
450 |
self.assertEqual(response.status_code, 201) |
451 |
reply = json.loads(response.content) |
452 |
self.assertEqual(reply.keys(), ['metadata']) |
453 |
return reply['metadata'] |
454 |
|
455 |
def update_server_metadata(self, server_id, metadata): |
456 |
path = '/api/v1.1/servers/%d/meta' % server_id
|
457 |
return self.update_metadata(path, metadata) |
458 |
|
459 |
def update_image_metadata(self, image_id, metadata): |
460 |
path = '/api/v1.1/images/%d/meta' % image_id
|
461 |
return self.update_metadata(path, metadata) |
462 |
|
463 |
def create_server_meta(self, server_id, meta): |
464 |
key = meta.keys()[0]
|
465 |
path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
|
466 |
data = json.dumps({'meta': meta})
|
467 |
response = self.client.put(path, data, content_type='application/json') |
468 |
self.assertEqual(response.status_code, 201) |
469 |
reply = json.loads(response.content) |
470 |
self.assertEqual(reply.keys(), ['meta']) |
471 |
response_meta = reply['meta']
|
472 |
self.assertEqual(response_meta, meta)
|
473 |
|
474 |
def get_all_server_metadata(self): |
475 |
metadata = defaultdict(dict)
|
476 |
for m in VirtualMachineMetadata.objects.all(): |
477 |
metadata[m.vm.id][m.meta_key] = m.meta_value |
478 |
return metadata
|
479 |
|
480 |
def get_all_image_metadata(self): |
481 |
metadata = defaultdict(dict)
|
482 |
for m in ImageMetadata.objects.all(): |
483 |
metadata[m.image.id][m.meta_key] = m.meta_value |
484 |
return metadata
|
485 |
|
486 |
def list_networks(self, detail=False): |
487 |
path = '/api/v1.1/networks'
|
488 |
if detail:
|
489 |
path += '/detail'
|
490 |
response = self.client.get(path)
|
491 |
self.assertTrue(response.status_code in (200, 203)) |
492 |
reply = json.loads(response.content) |
493 |
self.assertEqual(reply.keys(), ['networks']) |
494 |
self.assertEqual(reply['networks'].keys(), ['values']) |
495 |
return reply['networks']['values'] |
496 |
|
497 |
def create_network(self, name): |
498 |
path = '/api/v1.1/networks'
|
499 |
data = json.dumps({'network': {'name': name}}) |
500 |
response = self.client.post(path, data, content_type='application/json') |
501 |
self.assertEqual(response.status_code, 202) |
502 |
reply = json.loads(response.content) |
503 |
self.assertEqual(reply.keys(), ['network']) |
504 |
return reply
|
505 |
|
506 |
def get_network_details(self, name): |
507 |
path = '/api/v1.1/networks/%s' % name
|
508 |
response = self.client.get(path)
|
509 |
self.assertEqual(response.status_code, 200) |
510 |
reply = json.loads(response.content) |
511 |
self.assertEqual(reply.keys(), ['network']) |
512 |
return reply['network'] |
513 |
|
514 |
def update_network_name(self, name, new_name): |
515 |
path = '/api/v1.1/networks/%s' % name
|
516 |
data = json.dumps({'network': {'name': new_name}}) |
517 |
response = self.client.put(path, data, content_type='application/json') |
518 |
self.assertEqual(response.status_code, 204) |
519 |
|
520 |
def delete_network(self, name): |
521 |
path = '/api/v1.1/networks/%s' % name
|
522 |
response = self.client.delete(path)
|
523 |
self.assertEqual(response.status_code, 204) |
524 |
|
525 |
def add_to_network(self, network_name, server_id): |
526 |
path = '/api/v1.1/networks/%s/action' % network_name
|
527 |
data = json.dumps({'add': {'serverRef': server_id}}) |
528 |
response = self.client.post(path, data, content_type='application/json') |
529 |
self.assertEqual(response.status_code, 202) |
530 |
|
531 |
def remove_from_network(self, network_name, server_id): |
532 |
path = '/api/v1.1/networks/%s/action' % network_name
|
533 |
data = json.dumps({'remove': {'serverRef': server_id}}) |
534 |
response = self.client.post(path, data, content_type='application/json') |
535 |
self.assertEqual(response.status_code, 202) |
536 |
|
537 |
|
538 |
def popdict(l, **kwargs): |
539 |
"""Pops a dict from list `l` based on the predicates given as `kwargs`."""
|
540 |
|
541 |
for i in range(len(l)): |
542 |
item = l[i] |
543 |
match = True
|
544 |
for key, val in kwargs.items(): |
545 |
if item[key] != val:
|
546 |
match = False
|
547 |
break
|
548 |
if match:
|
549 |
del l[i]
|
550 |
return item
|
551 |
return None |
552 |
|
553 |
|
554 |
class ListImages(BaseTestCase): |
555 |
IMAGES = 10
|
556 |
|
557 |
def test_list_images(self): |
558 |
images = self.list_images()
|
559 |
keys = set(['id', 'name']) |
560 |
for img in Image.objects.all(): |
561 |
image = popdict(images, id=img.id) |
562 |
self.assertTrue(image is not None) |
563 |
self.assertEqual(set(image.keys()), keys) |
564 |
self.assertEqual(image['id'], img.id) |
565 |
self.assertEqual(image['name'], img.name) |
566 |
self.assertEqual(images, [])
|
567 |
|
568 |
def test_list_images_detail(self): |
569 |
images = self.list_images(detail=True) |
570 |
keys = set(['id', 'name', 'updated', 'created', 'status', 'progress']) |
571 |
for img in Image.objects.all(): |
572 |
image = popdict(images, id=img.id) |
573 |
self.assertTrue(image is not None) |
574 |
self.assertEqual(set(image.keys()), keys) |
575 |
self.assertEqual(image['id'], img.id) |
576 |
self.assertEqual(image['name'], img.name) |
577 |
self.assertEqual(image['status'], img.state) |
578 |
self.assertEqual(image['progress'], 100 if img.state == 'ACTIVE' else 0) |
579 |
self.assertEqual(images, [])
|
580 |
|
581 |
|
582 |
class ListServerMetadata(BaseTestCase): |
583 |
SERVERS = 5
|
584 |
SERVER_METADATA = 100
|
585 |
|
586 |
def test_list_metadata(self): |
587 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
588 |
for vm in VirtualMachine.objects.all(): |
589 |
response_metadata = self.list_server_metadata(vm.id)
|
590 |
self.assertEqual(response_metadata, metadata[vm.id])
|
591 |
|
592 |
def test_invalid_server(self): |
593 |
with AssertInvariant(self.get_all_server_metadata): |
594 |
response = self.client.get('/api/v1.1/servers/0/meta') |
595 |
self.assertItemNotFound(response)
|
596 |
|
597 |
|
598 |
class UpdateServerMetadata(BaseTestCase): |
599 |
SERVER_METADATA = 10
|
600 |
|
601 |
def test_update_metadata(self): |
602 |
metadata = self.get_all_server_metadata()
|
603 |
server_id = choice(metadata.keys()) |
604 |
new_metadata = {} |
605 |
for key in sample(metadata[server_id].keys(), 3): |
606 |
new_metadata[key] = 'New %s value' % key
|
607 |
response_metadata = self.update_server_metadata(server_id, new_metadata)
|
608 |
self.assertEqual(response_metadata, new_metadata)
|
609 |
metadata[server_id].update(new_metadata) |
610 |
self.assertEqual(metadata, self.get_all_server_metadata()) |
611 |
|
612 |
def test_does_not_create(self): |
613 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
614 |
server_id = choice(metadata.keys()) |
615 |
new_metadata = {'Foo': 'Bar'} |
616 |
response_metadata = self.update_server_metadata(server_id, new_metadata)
|
617 |
self.assertEqual(response_metadata, {})
|
618 |
|
619 |
def test_invalid_data(self): |
620 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
621 |
server_id = choice(metadata.keys()) |
622 |
path = '/api/v1.1/servers/%d/meta' % server_id
|
623 |
response = self.client.post(path, 'metadata', content_type='application/json') |
624 |
self.assertBadRequest(response)
|
625 |
|
626 |
def test_invalid_server(self): |
627 |
with AssertInvariant(self.get_all_server_metadata): |
628 |
path = '/api/v1.1/servers/0/meta'
|
629 |
data = json.dumps({'metadata': {'Key1': 'A Value'}}) |
630 |
response = self.client.post(path, data, content_type='application/json') |
631 |
self.assertItemNotFound(response)
|
632 |
|
633 |
|
634 |
class GetServerMetadataItem(BaseTestCase): |
635 |
SERVERS = 5
|
636 |
SERVER_METADATA = 100
|
637 |
|
638 |
def test_get_metadata_item(self): |
639 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
640 |
server_id = choice(metadata.keys()) |
641 |
key = choice(metadata[server_id].keys()) |
642 |
path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
|
643 |
response = self.client.get(path)
|
644 |
self.assertTrue(response.status_code in (200, 203)) |
645 |
reply = json.loads(response.content) |
646 |
self.assertEqual(reply['meta'], {key: metadata[server_id][key]}) |
647 |
|
648 |
def test_invalid_key(self): |
649 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
650 |
server_id = choice(metadata.keys()) |
651 |
response = self.client.get('/api/v1.1/servers/%d/meta/foo' % server_id) |
652 |
self.assertItemNotFound(response)
|
653 |
|
654 |
def test_invalid_server(self): |
655 |
with AssertInvariant(self.get_all_server_metadata): |
656 |
response = self.client.get('/api/v1.1/servers/0/meta/foo') |
657 |
self.assertItemNotFound(response)
|
658 |
|
659 |
|
660 |
class CreateServerMetadataItem(BaseTestCase): |
661 |
SERVER_METADATA = 10
|
662 |
|
663 |
def test_create_metadata(self): |
664 |
metadata = self.get_all_server_metadata()
|
665 |
server_id = choice(metadata.keys()) |
666 |
meta = {'Foo': 'Bar'} |
667 |
self.create_server_meta(server_id, meta)
|
668 |
metadata[server_id].update(meta) |
669 |
self.assertEqual(metadata, self.get_all_server_metadata()) |
670 |
|
671 |
def test_update_metadata(self): |
672 |
metadata = self.get_all_server_metadata()
|
673 |
server_id = choice(metadata.keys()) |
674 |
key = choice(metadata[server_id].keys()) |
675 |
meta = {key: 'New Value'}
|
676 |
self.create_server_meta(server_id, meta)
|
677 |
metadata[server_id].update(meta) |
678 |
self.assertEqual(metadata, self.get_all_server_metadata()) |
679 |
|
680 |
def test_invalid_server(self): |
681 |
with AssertInvariant(self.get_all_server_metadata): |
682 |
path = '/api/v1.1/servers/0/meta/foo'
|
683 |
data = json.dumps({'meta': {'foo': 'bar'}}) |
684 |
response = self.client.put(path, data, content_type='application/json') |
685 |
self.assertItemNotFound(response)
|
686 |
|
687 |
def test_invalid_key(self): |
688 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
689 |
server_id = choice(metadata.keys()) |
690 |
path = '/api/v1.1/servers/%d/meta/baz' % server_id
|
691 |
data = json.dumps({'meta': {'foo': 'bar'}}) |
692 |
response = self.client.put(path, data, content_type='application/json') |
693 |
self.assertBadRequest(response)
|
694 |
|
695 |
def test_invalid_data(self): |
696 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
697 |
server_id = choice(metadata.keys()) |
698 |
path = '/api/v1.1/servers/%d/meta/foo' % server_id
|
699 |
response = self.client.put(path, 'meta', content_type='application/json') |
700 |
self.assertBadRequest(response)
|
701 |
|
702 |
|
703 |
class DeleteServerMetadataItem(BaseTestCase): |
704 |
SERVER_METADATA = 10
|
705 |
|
706 |
def test_delete_metadata(self): |
707 |
metadata = self.get_all_server_metadata()
|
708 |
server_id = choice(metadata.keys()) |
709 |
key = choice(metadata[server_id].keys()) |
710 |
path = '/api/v1.1/servers/%d/meta/%s' % (server_id, key)
|
711 |
response = self.client.delete(path)
|
712 |
self.assertEqual(response.status_code, 204) |
713 |
metadata[server_id].pop(key) |
714 |
self.assertEqual(metadata, self.get_all_server_metadata()) |
715 |
|
716 |
def test_invalid_server(self): |
717 |
with AssertInvariant(self.get_all_server_metadata): |
718 |
response = self.client.delete('/api/v1.1/servers/9/meta/Key1') |
719 |
self.assertItemNotFound(response)
|
720 |
|
721 |
def test_invalid_key(self): |
722 |
with AssertInvariant(self.get_all_server_metadata) as metadata: |
723 |
server_id = choice(metadata.keys()) |
724 |
path = '/api/v1.1/servers/%d/meta/foo' % server_id
|
725 |
response = self.client.delete(path)
|
726 |
self.assertItemNotFound(response)
|
727 |
|
728 |
|
729 |
class ListImageMetadata(BaseTestCase): |
730 |
IMAGES = 5
|
731 |
IMAGE_METADATA = 100
|
732 |
|
733 |
def test_list_metadata(self): |
734 |
with AssertInvariant(self.get_all_image_metadata) as metadata: |
735 |
for image in Image.objects.all(): |
736 |
response_metadata = self.list_image_metadata(image.id)
|
737 |
self.assertEqual(response_metadata, metadata[image.id])
|
738 |
|
739 |
def test_invalid_image(self): |
740 |
with AssertInvariant(self.get_all_image_metadata): |
741 |
response = self.client.get('/api/v1.1/images/0/meta') |
742 |
self.assertItemNotFound(response)
|
743 |
|
744 |
class UpdateImageMetadata(BaseTestCase): |
745 |
IMAGE_METADATA = 10
|
746 |
|
747 |
def test_update_metadata(self): |
748 |
metadata = self.get_all_image_metadata()
|
749 |
image_id = choice(metadata.keys()) |
750 |
new_metadata = {} |
751 |
for key in sample(metadata[image_id].keys(), 3): |
752 |
new_metadata[key] = 'New %s value' % key
|
753 |
response_metadata = self.update_image_metadata(image_id, new_metadata)
|
754 |
self.assertEqual(response_metadata, new_metadata)
|
755 |
metadata[image_id].update(new_metadata) |
756 |
self.assertEqual(metadata, self.get_all_image_metadata()) |
757 |
|
758 |
def test_does_not_create(self): |
759 |
with AssertInvariant(self.get_all_image_metadata) as metadata: |
760 |
image_id = choice(metadata.keys()) |
761 |
new_metadata = {'Foo': 'Bar'} |
762 |
response_metadata = self.update_image_metadata(image_id, new_metadata)
|
763 |
self.assertEqual(response_metadata, {})
|
764 |
|
765 |
def test_invalid_data(self): |
766 |
with AssertInvariant(self.get_all_image_metadata) as metadata: |
767 |
image_id = choice(metadata.keys()) |
768 |
path = '/api/v1.1/images/%d/meta' % image_id
|
769 |
response = self.client.post(path, 'metadata', content_type='application/json') |
770 |
self.assertBadRequest(response)
|
771 |
|
772 |
def test_invalid_server(self): |
773 |
with AssertInvariant(self.get_all_image_metadata): |
774 |
path = '/api/v1.1/images/0/meta'
|
775 |
data = json.dumps({'metadata': {'Key1': 'A Value'}}) |
776 |
response = self.client.post(path, data, content_type='application/json') |
777 |
self.assertItemNotFound(response)
|
778 |
|
779 |
|
780 |
class ServerVNCConsole(BaseTestCase): |
781 |
SERVERS = 1
|
782 |
|
783 |
def test_not_active_server(self): |
784 |
"""Test console req for server not in ACTIVE state returns badRequest"""
|
785 |
server_id = choice(VirtualMachine.objects.all()).id |
786 |
path = '/api/v1.1/servers/%d/action' % server_id
|
787 |
data = json.dumps({'console': {'type': 'vnc'}}) |
788 |
response = self.client.post(path, data, content_type='application/json') |
789 |
self.assertBadRequest(response)
|
790 |
|
791 |
def test_active_server(self): |
792 |
"""Test console req for ACTIVE server"""
|
793 |
server_id = choice(VirtualMachine.objects.all()).id |
794 |
# FIXME: Start the server properly, instead of tampering with the DB
|
795 |
vm = choice(VirtualMachine.objects.all()) |
796 |
vm.operstate = 'STARTED'
|
797 |
vm.save() |
798 |
server_id = vm.id |
799 |
|
800 |
path = '/api/v1.1/servers/%d/action' % server_id
|
801 |
data = json.dumps({'console': {'type': 'vnc'}}) |
802 |
response = self.client.post(path, data, content_type='application/json') |
803 |
self.assertEqual(response.status_code, 200) |
804 |
reply = json.loads(response.content) |
805 |
self.assertEqual(reply.keys(), ['console']) |
806 |
console = reply['console']
|
807 |
self.assertEqual(console['type'], 'vnc') |
808 |
self.assertEqual(set(console.keys()), set(['type', 'host', 'port', 'password'])) |
809 |
|
810 |
|
811 |
class ListNetworks(BaseTestCase): |
812 |
SERVERS = 5
|
813 |
NETWORKS = 5
|
814 |
|
815 |
def setUp(self): |
816 |
BaseTestCase.setUp(self)
|
817 |
machines = VirtualMachine.objects.all() |
818 |
for network in Network.objects.all(): |
819 |
n = randint(0, self.SERVERS) |
820 |
network.machines.add(*sample(machines, n)) |
821 |
network.save() |
822 |
|
823 |
def test_list_networks(self): |
824 |
networks = self.list_networks()
|
825 |
for net in Network.objects.all(): |
826 |
popdict(networks, name=net.name) |
827 |
self.assertEqual(networks, [])
|
828 |
|
829 |
def test_list_networks_detail(self): |
830 |
networks = self.list_networks(detail=True) |
831 |
for net in Network.objects.all(): |
832 |
network = popdict(networks, name=net.name) |
833 |
machines = set(vm.id for vm in net.machines.all()) |
834 |
self.assertEqual(set(network['servers']['values']), machines) |
835 |
self.assertEqual(networks, [])
|
836 |
|
837 |
|
838 |
class CreateNetwork(BaseTestCase): |
839 |
def test_create_network(self): |
840 |
self.assertEqual(self.list_networks(), []) |
841 |
self.create_network('net') |
842 |
networks = self.list_networks()
|
843 |
self.assertEqual(len(networks), 1) |
844 |
network = networks[0]
|
845 |
self.assertEqual(network['name'], 'net') |
846 |
|
847 |
|
848 |
class GetNetworkDetails(BaseTestCase): |
849 |
SERVERS = 5
|
850 |
NETWORKS = 1
|
851 |
|
852 |
def test_get_network_details(self): |
853 |
servers = VirtualMachine.objects.all() |
854 |
network = Network.objects.all()[0]
|
855 |
name = network.name |
856 |
|
857 |
net = self.get_network_details(name)
|
858 |
self.assertEqual(net['servers']['values'], []) |
859 |
|
860 |
server_id = choice(servers).id |
861 |
self.add_to_network(name, server_id)
|
862 |
net = self.get_network_details(name)
|
863 |
self.assertEqual(net['servers']['values'], [server_id]) |
864 |
|
865 |
|
866 |
class UpdateNetworkName(BaseTestCase): |
867 |
NETWORKS = 5
|
868 |
|
869 |
def test_update_network_name(self): |
870 |
networks = self.list_networks(detail=True) |
871 |
network = choice(networks) |
872 |
name = network['name']
|
873 |
new_name = name + '_2'
|
874 |
self.update_network_name(name, new_name)
|
875 |
|
876 |
network['name'] = new_name
|
877 |
self.assertEqual(self.get_network_details(new_name), network) |
878 |
|
879 |
response = self.client.get('/api/v1.1/networks/' + name) |
880 |
self.assertItemNotFound(response)
|
881 |
|
882 |
|
883 |
class DeleteNetwork(BaseTestCase): |
884 |
NETWORKS = 5
|
885 |
|
886 |
def test_delete_network(self): |
887 |
networks = self.list_networks()
|
888 |
network = choice(networks) |
889 |
name = network['name']
|
890 |
self.delete_network(name)
|
891 |
|
892 |
response = self.client.get('/api/v1.1/networks/' + name) |
893 |
self.assertItemNotFound(response)
|
894 |
|
895 |
networks.remove(network) |
896 |
self.assertEqual(self.list_networks(), networks) |
897 |
|
898 |
|
899 |
class NetworkActions(BaseTestCase): |
900 |
SERVERS = 20
|
901 |
NETWORKS = 1
|
902 |
|
903 |
def test_add_remove_server(self): |
904 |
server_ids = [vm.id for vm in VirtualMachine.objects.all()] |
905 |
network = self.list_networks(detail=True)[0] |
906 |
name = network['name']
|
907 |
|
908 |
to_add = set(sample(server_ids, 10)) |
909 |
for server_id in to_add: |
910 |
self.add_to_network(name, server_id)
|
911 |
net = self.get_network_details(name)
|
912 |
self.assertTrue(server_id in net['servers']['values']) |
913 |
|
914 |
net = self.get_network_details(name)
|
915 |
self.assertEqual(set(net['servers']['values']), to_add) |
916 |
|
917 |
to_remove = set(sample(to_add, 5)) |
918 |
for server_id in to_remove: |
919 |
self.remove_from_network(name, server_id)
|
920 |
net = self.get_network_details(name)
|
921 |
self.assertTrue(server_id not in net['servers']['values']) |
922 |
|
923 |
net = self.get_network_details(name)
|
924 |
self.assertEqual(set(net['servers']['values']), to_add - to_remove) |