Merge lp:~devcamcar/django-nova/improve_unittests into lp:django-nova
- improve_unittests
- Merge into trunk
Proposed by
Devin Carlen
Status: | Merged |
---|---|
Approved by: | Devin Carlen |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11 |
Proposed branch: | lp:~devcamcar/django-nova/improve_unittests |
Merge into: | lp:django-nova |
Diff against target: |
885 lines (+490/-54) 17 files modified
buildout.cfg (+1/-1) setup.py (+1/-1) src/django_nova/forms.py (+3/-3) src/django_nova/manager.py (+11/-1) src/django_nova/models.py (+5/-0) src/django_nova/shortcuts.py (+3/-2) src/django_nova/tests/__init__.py (+1/-0) src/django_nova/tests/urls.py (+32/-0) src/django_nova/tests/view_tests/__init__.py (+3/-0) src/django_nova/tests/view_tests/base.py (+51/-0) src/django_nova/tests/view_tests/image_tests.py (+210/-0) src/django_nova/tests/view_tests/instance_tests.py (+45/-0) src/django_nova/tests/view_tests/keypair_tests.py (+71/-0) src/django_nova/testsettings.py (+17/-3) src/django_nova/views/images.py (+20/-27) src/django_nova/views/instances.py (+11/-11) src/django_nova/views/keypairs.py (+5/-5) |
To merge this branch: | bzr merge lp:~devcamcar/django-nova/improve_unittests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen | Approve | ||
Review via email: mp+47481@code.launchpad.net |
Commit message
Description of the change
Results of refactoring view tests and adding mox. Still in progress but merging in what's there to date.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'buildout.cfg' |
2 | --- buildout.cfg 2011-01-12 20:02:06 +0000 |
3 | +++ buildout.cfg 2011-01-25 23:54:53 +0000 |
4 | @@ -10,7 +10,7 @@ |
5 | |
6 | [django] |
7 | recipe = djangorecipe |
8 | -version = 1.2.3 |
9 | +version = 1.2.4 |
10 | project = django_nova |
11 | projectegg = django_nova |
12 | settings = testsettings |
13 | |
14 | === modified file 'setup.py' |
15 | --- setup.py 2011-01-12 20:02:06 +0000 |
16 | +++ setup.py 2011-01-25 23:54:53 +0000 |
17 | @@ -15,7 +15,7 @@ |
18 | author_email = 'devin.carlen@gmail.com', |
19 | packages = find_packages('src'), |
20 | package_dir = {'': 'src'}, |
21 | - install_requires = ['setuptools'], |
22 | + install_requires = ['setuptools', 'boto==1.9b', 'mox>=0.5.0'], |
23 | classifiers = [ |
24 | 'Development Status :: 4 - Beta', |
25 | 'Framework :: Django', |
26 | |
27 | === modified file 'src/django_nova/forms.py' |
28 | --- src/django_nova/forms.py 2011-01-16 03:46:33 +0000 |
29 | +++ src/django_nova/forms.py 2011-01-25 23:54:53 +0000 |
30 | @@ -49,13 +49,13 @@ |
31 | |
32 | def get_instance_choices(project): |
33 | choices = [(i.id, i.id) for i in project.get_instances()] |
34 | - if len(choices) == 0: |
35 | + if not len(choices): |
36 | choices = [('', 'none available')] |
37 | return choices |
38 | |
39 | def get_key_pair_choices(project): |
40 | choices = [(k.name, k.name) for k in project.get_key_pairs()] |
41 | - if len(choices) == 0: |
42 | + if not len(choices): |
43 | choices = [('', 'none available')] |
44 | return choices |
45 | |
46 | @@ -68,7 +68,7 @@ |
47 | def get_available_volume_choices(project): |
48 | choices = [(v.id, '%s %s - %dGB' % (v.id, v.displayName, v.size)) for v in \ |
49 | project.get_volumes() if v.status != "in-use"] |
50 | - if len(choices) == 0: |
51 | + if not len(choices): |
52 | choices = [('', 'none available')] |
53 | return choices |
54 | |
55 | |
56 | === modified file 'src/django_nova/manager.py' |
57 | --- src/django_nova/manager.py 2011-01-15 09:27:24 +0000 |
58 | +++ src/django_nova/manager.py 2011-01-25 23:54:53 +0000 |
59 | @@ -87,6 +87,16 @@ |
60 | return conn.get_object('UpdateImage', params, boto.ec2.image.Image) |
61 | |
62 | @wrap_nova_error |
63 | + def modify_image_attribute(self, image_id, attribute=None, operation=None, |
64 | + groups='all'): |
65 | + conn = self.get_nova_connection() |
66 | + return conn.modify_image_attribute(image_id, |
67 | + attribute='launchPermission', |
68 | + operation='remove', |
69 | + groups='all',) |
70 | + |
71 | + |
72 | + @wrap_nova_error |
73 | def run_instances(self, image_id, **kwargs): |
74 | """ |
75 | Runs instances of the specified image id. |
76 | @@ -201,7 +211,7 @@ |
77 | """ |
78 | Indicates whether a security group with the specified name exists in this project. |
79 | """ |
80 | - return self.get_security_group(name) != None |
81 | + return self.get_security_group(name) is not None |
82 | |
83 | @wrap_nova_error |
84 | def create_security_group(self, name, description): |
85 | |
86 | === modified file 'src/django_nova/models.py' |
87 | --- src/django_nova/models.py 2011-01-12 20:02:06 +0000 |
88 | +++ src/django_nova/models.py 2011-01-25 23:54:53 +0000 |
89 | @@ -107,6 +107,11 @@ |
90 | """ |
91 | Creates a Nova User when a new Django User is created. |
92 | """ |
93 | + |
94 | + # NOTE(devcamcar): If running unit tests, don't use a real endpoint. |
95 | + if settings.NOVA_DEFAULT_ENDPOINT == 'none': |
96 | + return |
97 | + |
98 | if created: |
99 | nova = get_nova_admin_connection() |
100 | if not nova.has_user(instance.username): |
101 | |
102 | === modified file 'src/django_nova/shortcuts.py' |
103 | --- src/django_nova/shortcuts.py 2011-01-17 06:58:19 +0000 |
104 | +++ src/django_nova/shortcuts.py 2011-01-25 23:54:53 +0000 |
105 | @@ -15,6 +15,7 @@ |
106 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
107 | # License for the specific language governing permissions and limitations |
108 | # under the License. |
109 | + |
110 | """ |
111 | Helper methods for commonly used operations. |
112 | """ |
113 | @@ -115,13 +116,13 @@ |
114 | user_has_modify_permissions = False |
115 | |
116 | # checks global roles, if user is a sysadmin they can modify image attribtues. |
117 | - if user_has_modify_permissions == False: |
118 | + if not user_has_modify_permissions: |
119 | for role in nova.get_user_roles(username): |
120 | if role.role == "sysadmin": |
121 | user_has_modify_permissions = True |
122 | |
123 | # checks project roles, if user is a sysadmin they can modify image attribtues. |
124 | - if user_has_modify_permissions == False: |
125 | + if not user_has_modify_permissions: |
126 | for role in nova.get_user_roles(username, project_name): |
127 | if role.role == "sysadmin": |
128 | user_has_modify_permissions = True |
129 | |
130 | === added directory 'src/django_nova/tests' |
131 | === added file 'src/django_nova/tests/__init__.py' |
132 | --- src/django_nova/tests/__init__.py 1970-01-01 00:00:00 +0000 |
133 | +++ src/django_nova/tests/__init__.py 2011-01-25 23:54:53 +0000 |
134 | @@ -0,0 +1,1 @@ |
135 | +from view_tests import * |
136 | \ No newline at end of file |
137 | |
138 | === added directory 'src/django_nova/tests/templates' |
139 | === added file 'src/django_nova/tests/templates/base-sidebar.html' |
140 | === added file 'src/django_nova/tests/urls.py' |
141 | --- src/django_nova/tests/urls.py 1970-01-01 00:00:00 +0000 |
142 | +++ src/django_nova/tests/urls.py 2011-01-25 23:54:53 +0000 |
143 | @@ -0,0 +1,32 @@ |
144 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
145 | + |
146 | +# Copyright 2010 United States Government as represented by the |
147 | +# Administrator of the National Aeronautics and Space Administration. |
148 | +# All Rights Reserved. |
149 | +# |
150 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
151 | +# not use this file except in compliance with the License. You may obtain |
152 | +# a copy of the License at |
153 | +# |
154 | +# http://www.apache.org/licenses/LICENSE-2.0 |
155 | +# |
156 | +# Unless required by applicable law or agreed to in writing, software |
157 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
158 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
159 | +# License for the specific language governing permissions and limitations |
160 | +# under the License. |
161 | + |
162 | +""" |
163 | +URL patterns for testing django-nova views. |
164 | +""" |
165 | + |
166 | +from django.conf.urls.defaults import * |
167 | +from django.conf.urls.defaults import * |
168 | + |
169 | + |
170 | +urlpatterns = patterns('', |
171 | + url(r'^projects/', include('django_nova.urls.project')), |
172 | + url(r'^region/', include('django_nova.urls.region')), |
173 | + url(r'^admin/projects/', include('django_nova.urls.admin_project')), |
174 | + url(r'^admin/roles/', include('django_nova.urls.admin_roles')), |
175 | +) |
176 | \ No newline at end of file |
177 | |
178 | === added directory 'src/django_nova/tests/view_tests' |
179 | === added file 'src/django_nova/tests/view_tests/__init__.py' |
180 | --- src/django_nova/tests/view_tests/__init__.py 1970-01-01 00:00:00 +0000 |
181 | +++ src/django_nova/tests/view_tests/__init__.py 2011-01-25 23:54:53 +0000 |
182 | @@ -0,0 +1,3 @@ |
183 | +from keypair_tests import * |
184 | +from image_tests import * |
185 | +from instance_tests import * |
186 | \ No newline at end of file |
187 | |
188 | === added file 'src/django_nova/tests/view_tests/base.py' |
189 | --- src/django_nova/tests/view_tests/base.py 1970-01-01 00:00:00 +0000 |
190 | +++ src/django_nova/tests/view_tests/base.py 2011-01-25 23:54:53 +0000 |
191 | @@ -0,0 +1,51 @@ |
192 | +import mox |
193 | + |
194 | +from django import test |
195 | +from django.conf import settings |
196 | +from django.contrib.auth import models as auth_models |
197 | +from django_nova import adminclient |
198 | +from django_nova import manager |
199 | +from django_nova import shortcuts |
200 | + |
201 | + |
202 | +TEST_PROJECT = 'test' |
203 | +TEST_USER = 'test' |
204 | +TEST_REGION = 'test' |
205 | + |
206 | + |
207 | +class BaseProjectViewTests(test.TestCase): |
208 | + def setUp(self): |
209 | + project = adminclient.ProjectInfo() |
210 | + project.projectname = TEST_PROJECT |
211 | + project.projectManagerId = TEST_USER |
212 | + |
213 | + self.mox = mox.Mox() |
214 | + self.user = auth_models.User.objects.create_user(TEST_USER, |
215 | + 'test@test.com', |
216 | + password='test') |
217 | + login = self.client.login(username=TEST_USER, password='test') |
218 | + self.failUnless(login, 'Unable to login') |
219 | + |
220 | + self.region = adminclient.RegionInfo(name=TEST_REGION, |
221 | + endpoint='http://test:8773/') |
222 | + self.project = manager.ProjectManager(self.user.username, |
223 | + project, |
224 | + self.region) |
225 | + self.mox.StubOutWithMock(shortcuts, 'get_project_or_404') |
226 | + shortcuts.get_project_or_404(mox.IgnoreArg(), |
227 | + 'test').AndReturn(self.project) |
228 | + |
229 | + def tearDown(self): |
230 | + self.mox.UnsetStubs() |
231 | + |
232 | + def assertRedirectsNoFollow(self, response, expected_url): |
233 | + self.assertEqual(response._headers['location'], |
234 | + ('Location', settings.TESTSERVER + expected_url)) |
235 | + self.assertEqual(response.status_code, 302) |
236 | + |
237 | + def create_key_pair_choices(self, key_names): |
238 | + return [(k, k) for k in key_names] |
239 | + |
240 | + def create_instance_type_choices(self): |
241 | + return [('m1.medium', 'm1.medium'), |
242 | + ('m1.large', 'm1.large')] |
243 | |
244 | === added file 'src/django_nova/tests/view_tests/image_tests.py' |
245 | --- src/django_nova/tests/view_tests/image_tests.py 1970-01-01 00:00:00 +0000 |
246 | +++ src/django_nova/tests/view_tests/image_tests.py 2011-01-25 23:54:53 +0000 |
247 | @@ -0,0 +1,210 @@ |
248 | +import boto.ec2.image |
249 | +import boto.ec2.instance |
250 | +import mox |
251 | + |
252 | +from django.core.urlresolvers import reverse |
253 | +from django_nova import forms |
254 | +from django_nova import shortcuts |
255 | +from django_nova.tests.view_tests.base import BaseProjectViewTests, TEST_PROJECT |
256 | + |
257 | + |
258 | +TEST_IMAGE_ID = 'ami_test' |
259 | +TEST_INSTANCE_ID = 'i-abcdefg' |
260 | +TEST_KEY = 'foo' |
261 | + |
262 | + |
263 | +class ImageViewTests(BaseProjectViewTests): |
264 | + def setUp(self): |
265 | + self.ami = boto.ec2.image.Image() |
266 | + self.ami.id = TEST_IMAGE_ID |
267 | + setattr(self.ami, 'displayName', TEST_IMAGE_ID) |
268 | + setattr(self.ami, 'description', TEST_IMAGE_ID) |
269 | + super(ImageViewTests, self).setUp() |
270 | + |
271 | + def test_index(self): |
272 | + self.mox.StubOutWithMock(self.project, 'get_images') |
273 | + self.mox.StubOutWithMock(forms, 'get_key_pair_choices') |
274 | + self.mox.StubOutWithMock(forms, 'get_instance_type_choices') |
275 | + |
276 | + self.project.get_images().AndReturn([]) |
277 | + forms.get_key_pair_choices(self.project).AndReturn([]) |
278 | + forms.get_instance_type_choices().AndReturn([]) |
279 | + |
280 | + self.mox.ReplayAll() |
281 | + |
282 | + res = self.client.get(reverse('nova_images', args=[TEST_PROJECT])) |
283 | + self.assertEqual(res.status_code, 200) |
284 | + self.assertTemplateUsed(res, 'django_nova/images/index.html') |
285 | + self.assertEqual(len(res.context['image_lists']), 3) |
286 | + |
287 | + self.mox.VerifyAll() |
288 | + |
289 | + def test_launch_form(self): |
290 | + self.mox.StubOutWithMock(self.project, 'get_image') |
291 | + self.mox.StubOutWithMock(forms, 'get_key_pair_choices') |
292 | + self.mox.StubOutWithMock(forms, 'get_instance_type_choices') |
293 | + |
294 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
295 | + forms.get_key_pair_choices(self.project).AndReturn([]) |
296 | + forms.get_instance_type_choices().AndReturn([]) |
297 | + |
298 | + self.mox.ReplayAll() |
299 | + |
300 | + args = [TEST_PROJECT, TEST_IMAGE_ID] |
301 | + res = self.client.get(reverse('nova_images_launch', args=args)) |
302 | + self.assertEqual(res.status_code, 200) |
303 | + self.assertTemplateUsed(res, 'django_nova/images/launch.html') |
304 | + self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID) |
305 | + |
306 | + self.mox.VerifyAll() |
307 | + |
308 | + def test_launch(self): |
309 | + instance = boto.ec2.instance.Instance() |
310 | + instance.id = TEST_INSTANCE_ID |
311 | + instance.image_id = TEST_IMAGE_ID |
312 | + reservation = boto.ec2.instance.Reservation() |
313 | + reservation.instances = [instance] |
314 | + |
315 | + self.mox.StubOutWithMock(forms, 'get_key_pair_choices') |
316 | + self.mox.StubOutWithMock(forms, 'get_instance_type_choices') |
317 | + self.mox.StubOutWithMock(self.project, 'run_instances') |
318 | + |
319 | + forms.get_key_pair_choices(self.project).AndReturn( |
320 | + self.create_key_pair_choices([TEST_KEY])) |
321 | + forms.get_instance_type_choices().AndReturn( |
322 | + self.create_instance_type_choices()) |
323 | + self.project.run_instances(TEST_IMAGE_ID, |
324 | + addressing_type=mox.IgnoreArg(), |
325 | + key_name=TEST_KEY, |
326 | + user_data='', |
327 | + instance_type='m1.medium', |
328 | + min_count='1', |
329 | + max_count='1').AndReturn(reservation) |
330 | + self.mox.ReplayAll() |
331 | + |
332 | + url = reverse('nova_images_launch', args=[TEST_PROJECT, TEST_IMAGE_ID]) |
333 | + data = {'key_name': TEST_KEY, |
334 | + 'count': '1', |
335 | + 'size': 'm1.medium', |
336 | + 'user_data': ''} |
337 | + res = self.client.post(url, data) |
338 | + self.assertRedirectsNoFollow(res, reverse('nova_instances', |
339 | + args=[TEST_PROJECT])) |
340 | + self.mox.VerifyAll() |
341 | + |
342 | + def test_detail(self): |
343 | + self.mox.StubOutWithMock(self.project, 'get_images') |
344 | + self.mox.StubOutWithMock(self.project, 'get_image') |
345 | + self.mox.StubOutWithMock(shortcuts, 'get_user_image_permissions') |
346 | + self.mox.StubOutWithMock(forms, 'get_key_pair_choices') |
347 | + self.mox.StubOutWithMock(forms, 'get_instance_type_choices') |
348 | + |
349 | + self.project.get_images().AndReturn([self.ami]) |
350 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
351 | + shortcuts.get_user_image_permissions(mox.IgnoreArg(), |
352 | + TEST_PROJECT).AndReturn(True) |
353 | + forms.get_key_pair_choices(self.project).AndReturn( |
354 | + self.create_key_pair_choices([TEST_KEY])) |
355 | + forms.get_instance_type_choices().AndReturn( |
356 | + self.create_instance_type_choices()) |
357 | + |
358 | + self.mox.ReplayAll() |
359 | + |
360 | + res = self.client.get(reverse('nova_images_detail', |
361 | + args=[TEST_PROJECT, TEST_IMAGE_ID])) |
362 | + self.assertEqual(res.status_code, 200) |
363 | + self.assertTemplateUsed(res, 'django_nova/images/index.html') |
364 | + self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID) |
365 | + |
366 | + self.mox.VerifyAll() |
367 | + |
368 | + def test_remove_form(self): |
369 | + self.mox.StubOutWithMock(self.project, 'get_image') |
370 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
371 | + self.mox.ReplayAll() |
372 | + |
373 | + res = self.client.get(reverse('nova_images_remove', |
374 | + args=[TEST_PROJECT, TEST_IMAGE_ID])) |
375 | + self.assertEqual(res.status_code, 200) |
376 | + self.assertTemplateUsed(res, 'django_nova/images/detail_list.html') |
377 | + self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID) |
378 | + |
379 | + self.mox.VerifyAll() |
380 | + |
381 | + def test_remove(self): |
382 | + self.mox.StubOutWithMock(self.project, 'deregister_image') |
383 | + self.project.deregister_image(TEST_IMAGE_ID).AndReturn(True) |
384 | + self.mox.ReplayAll() |
385 | + |
386 | + res = self.client.post(reverse('nova_images_remove', |
387 | + args=[TEST_PROJECT, TEST_IMAGE_ID])) |
388 | + self.assertRedirectsNoFollow(res, reverse('nova_images', |
389 | + args=[TEST_PROJECT])) |
390 | + |
391 | + self.mox.VerifyAll() |
392 | + |
393 | + def test_make_public(self): |
394 | + self.mox.StubOutWithMock(self.project, 'get_image') |
395 | + self.mox.StubOutWithMock(self.project, 'modify_image_attribute') |
396 | + |
397 | + self.ami.is_public = False |
398 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
399 | + self.project.modify_image_attribute(TEST_IMAGE_ID, |
400 | + attribute='launchPermission', |
401 | + operation='add').AndReturn(True) |
402 | + self.mox.ReplayAll() |
403 | + |
404 | + res = self.client.post(reverse('nova_images_privacy', |
405 | + args=[TEST_PROJECT, TEST_IMAGE_ID])) |
406 | + self.assertRedirectsNoFollow(res, reverse('nova_images_detail', |
407 | + args=[TEST_PROJECT, TEST_IMAGE_ID])) |
408 | + self.mox.VerifyAll() |
409 | + |
410 | + def test_make_private(self): |
411 | + self.mox.StubOutWithMock(self.project, 'get_image') |
412 | + self.mox.StubOutWithMock(self.project, 'modify_image_attribute') |
413 | + |
414 | + self.ami.is_public = True |
415 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
416 | + self.project.modify_image_attribute(TEST_IMAGE_ID, |
417 | + attribute='launchPermission', |
418 | + operation='remove').AndReturn(True) |
419 | + self.mox.ReplayAll() |
420 | + |
421 | + args = [TEST_PROJECT, TEST_IMAGE_ID] |
422 | + res = self.client.post(reverse('nova_images_privacy', args=args)) |
423 | + self.assertRedirectsNoFollow(res, reverse('nova_images_detail', |
424 | + args=args)) |
425 | + self.mox.VerifyAll() |
426 | + |
427 | + def test_update_form(self): |
428 | + self.mox.StubOutWithMock(self.project, 'get_image') |
429 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
430 | + self.mox.ReplayAll() |
431 | + |
432 | + args = [TEST_PROJECT, TEST_IMAGE_ID] |
433 | + res = self.client.get(reverse('nova_images_update', args=args)) |
434 | + self.assertEqual(res.status_code, 200) |
435 | + self.assertTemplateUsed(res, 'django_nova/images/edit.html') |
436 | + self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID) |
437 | + |
438 | + self.mox.VerifyAll() |
439 | + |
440 | + def test_update(self): |
441 | + self.mox.StubOutWithMock(self.project, 'get_image') |
442 | + self.mox.StubOutWithMock(self.project, 'update_image') |
443 | + |
444 | + self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami) |
445 | + self.project.update_image(TEST_IMAGE_ID, 'test', 'test').AndReturn(True) |
446 | + |
447 | + self.mox.ReplayAll() |
448 | + |
449 | + args = [TEST_PROJECT, TEST_IMAGE_ID] |
450 | + data = {'nickname': 'test', |
451 | + 'description': 'test'} |
452 | + url = reverse('nova_images_update', args=args) |
453 | + res = self.client.post(url, data) |
454 | + expected_url = reverse('nova_images_detail', args=args) |
455 | + self.assertRedirectsNoFollow(res, expected_url) |
456 | + |
457 | + self.mox.VerifyAll() |
458 | |
459 | === added file 'src/django_nova/tests/view_tests/instance_tests.py' |
460 | --- src/django_nova/tests/view_tests/instance_tests.py 1970-01-01 00:00:00 +0000 |
461 | +++ src/django_nova/tests/view_tests/instance_tests.py 2011-01-25 23:54:53 +0000 |
462 | @@ -0,0 +1,45 @@ |
463 | +import boto.ec2.instance |
464 | +import mox |
465 | + |
466 | +from django.core.urlresolvers import reverse |
467 | +from django_nova.tests.view_tests.base import BaseProjectViewTests, TEST_PROJECT |
468 | + |
469 | + |
470 | +TEST_INSTANCE_ID = 'i-abcdefgh' |
471 | + |
472 | + |
473 | +class InstanceViewTests(BaseProjectViewTests): |
474 | + def test_index(self): |
475 | + self.mox.StubOutWithMock(self.project, 'get_instances') |
476 | + self.project.get_instances().AndReturn([]) |
477 | + |
478 | + self.mox.ReplayAll() |
479 | + |
480 | + res = self.client.get(reverse('nova_instances', args=[TEST_PROJECT])) |
481 | + self.assertEqual(res.status_code, 200) |
482 | + self.assertTemplateUsed(res, 'django_nova/instances/index.html') |
483 | + self.assertEqual(len(res.context['instances']), 0) |
484 | + |
485 | + self.mox.VerifyAll() |
486 | + |
487 | + def test_detail(self): |
488 | + instance = boto.ec2.instance.Instance() |
489 | + instance.id = TEST_INSTANCE_ID |
490 | + instance.displayName = instance.id |
491 | + instance.displayDescription = instance.id |
492 | + |
493 | + self.mox.StubOutWithMock(self.project, 'get_instance') |
494 | + self.project.get_instance(instance.id).AndReturn(instance) |
495 | + self.mox.StubOutWithMock(self.project, 'get_instances') |
496 | + self.project.get_instances().AndReturn([instance]) |
497 | + |
498 | + self.mox.ReplayAll() |
499 | + |
500 | + res = self.client.get(reverse('nova_instances_detail', |
501 | + args=[TEST_PROJECT, TEST_INSTANCE_ID])) |
502 | + self.assertEqual(res.status_code, 200) |
503 | + self.assertTemplateUsed(res, 'django_nova/instances/index.html') |
504 | + self.assertEqual(res.context['selected_instance'].id, instance.id) |
505 | + |
506 | + self.mox.VerifyAll() |
507 | + |
508 | |
509 | === added file 'src/django_nova/tests/view_tests/keypair_tests.py' |
510 | --- src/django_nova/tests/view_tests/keypair_tests.py 1970-01-01 00:00:00 +0000 |
511 | +++ src/django_nova/tests/view_tests/keypair_tests.py 2011-01-25 23:54:53 +0000 |
512 | @@ -0,0 +1,71 @@ |
513 | +import boto.ec2.keypair |
514 | +import mox |
515 | + |
516 | +from django.core.urlresolvers import reverse |
517 | +from django_nova.tests.view_tests.base import BaseProjectViewTests, TEST_PROJECT |
518 | + |
519 | + |
520 | +TEST_KEY = 'test_key' |
521 | + |
522 | + |
523 | +class KeyPairViewTests(BaseProjectViewTests): |
524 | + def test_index(self): |
525 | + self.mox.StubOutWithMock(self.project, 'get_key_pairs') |
526 | + self.project.get_key_pairs().AndReturn([]) |
527 | + |
528 | + self.mox.ReplayAll() |
529 | + |
530 | + response = self.client.get(reverse('nova_keypairs', |
531 | + args=[TEST_PROJECT])) |
532 | + self.assertEqual(response.status_code, 200) |
533 | + self.assertTemplateUsed(response, 'django_nova/keypairs/index.html') |
534 | + self.assertEqual(len(response.context['keypairs']), 0) |
535 | + |
536 | + self.mox.VerifyAll() |
537 | + |
538 | + def test_add_keypair(self): |
539 | + key = boto.ec2.keypair.KeyPair() |
540 | + key.name = TEST_KEY |
541 | + |
542 | + self.mox.StubOutWithMock(self.project, 'create_key_pair') |
543 | + self.project.create_key_pair(key.name).AndReturn(key) |
544 | + self.mox.StubOutWithMock(self.project, 'has_key_pair') |
545 | + self.project.has_key_pair(key.name).AndReturn(False) |
546 | + |
547 | + self.mox.ReplayAll() |
548 | + |
549 | + url = reverse('nova_keypairs_add', args=[TEST_PROJECT]) |
550 | + data = {'js': '0', 'name': key.name} |
551 | + res = self.client.post(url, |
552 | + data) |
553 | + self.assertEqual(res.status_code, 200) |
554 | + self.assertEqual(res['Content-Type'], 'application/binary') |
555 | + |
556 | + self.mox.VerifyAll() |
557 | + |
558 | + def test_delete_keypair(self): |
559 | + self.mox.StubOutWithMock(self.project, 'delete_key_pair') |
560 | + self.project.delete_key_pair(TEST_KEY).AndReturn(None) |
561 | + |
562 | + self.mox.ReplayAll() |
563 | + |
564 | + data = {'key_name': TEST_KEY} |
565 | + url = reverse('nova_keypairs_delete', args=[TEST_PROJECT]) |
566 | + res = self.client.post(url, data) |
567 | + self.assertRedirectsNoFollow(res, reverse('nova_keypairs', |
568 | + args=[TEST_PROJECT])) |
569 | + |
570 | + self.mox.VerifyAll() |
571 | + |
572 | + def test_download_keypair(self): |
573 | + material = 'abcdefgh' |
574 | + session = self.client.session |
575 | + session['key.%s' % TEST_KEY] = material |
576 | + session.save() |
577 | + |
578 | + res = self.client.get(reverse('nova_keypairs_download', |
579 | + args=['test', TEST_KEY])) |
580 | + self.assertEqual(res.status_code, 200) |
581 | + self.assertEqual(res['Content-Type'], 'application/binary') |
582 | + self.assertContains(res, material) |
583 | + |
584 | |
585 | === modified file 'src/django_nova/testsettings.py' |
586 | --- src/django_nova/testsettings.py 2011-01-12 20:02:06 +0000 |
587 | +++ src/django_nova/testsettings.py 2011-01-25 23:54:53 +0000 |
588 | @@ -1,5 +1,19 @@ |
589 | +import os |
590 | + |
591 | +ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) |
592 | +DEBUG = True |
593 | +TESTSERVER = 'http://testserver' |
594 | DATABASE_ENGINE = 'sqlite3' |
595 | DATABASE_NAME = '/tmp/django-nova.db' |
596 | -INSTALLED_APPS = ['django_nova'] |
597 | -ROOT_URLCONF = ['django_nova.urls'] |
598 | - |
599 | +INSTALLED_APPS = ['django.contrib.auth', |
600 | + 'django.contrib.contenttypes', |
601 | + 'django.contrib.sessions', |
602 | + 'django_nova'] |
603 | +ROOT_URLCONF = 'django_nova.tests.urls' |
604 | +TEMPLATE_DIRS = ( |
605 | + os.path.join(ROOT_PATH, 'tests', 'templates') |
606 | +) |
607 | +NOVA_DEFAULT_ENDPOINT = 'none' |
608 | +NOVA_DEFAULT_REGION = 'test' |
609 | +NOVA_ACCESS_KEY = 'test' |
610 | +NOVA_SECRET_KEY = 'test' |
611 | |
612 | === modified file 'src/django_nova/views/images.py' |
613 | --- src/django_nova/views/images.py 2011-01-24 23:17:58 +0000 |
614 | +++ src/django_nova/views/images.py 2011-01-25 23:54:53 +0000 |
615 | @@ -30,8 +30,8 @@ |
616 | from django.shortcuts import redirect, render_to_response |
617 | from django_nova import exceptions |
618 | from django_nova import forms |
619 | +from django_nova import shortcuts |
620 | from django_nova.exceptions import handle_nova_error |
621 | -from django_nova.shortcuts import get_project_or_404, get_user_image_permissions |
622 | |
623 | |
624 | def _image_lists(images, project_id): |
625 | @@ -52,7 +52,7 @@ |
626 | @login_required |
627 | @handle_nova_error |
628 | def index(request, project_id): |
629 | - project = get_project_or_404(request, project_id) |
630 | + project = shortcuts.get_project_or_404(request, project_id) |
631 | images = project.get_images() |
632 | |
633 | return render_to_response('django_nova/images/index.html', { |
634 | @@ -66,7 +66,7 @@ |
635 | @login_required |
636 | @handle_nova_error |
637 | def launch(request, project_id, image_id): |
638 | - project = get_project_or_404(request, project_id) |
639 | + project = shortcuts.get_project_or_404(request, project_id) |
640 | |
641 | if request.method == 'POST': |
642 | form = forms.LaunchInstanceForm(project, request.POST) |
643 | @@ -107,14 +107,15 @@ |
644 | @login_required |
645 | @handle_nova_error |
646 | def detail(request, project_id, image_id): |
647 | - project = get_project_or_404(request, project_id) |
648 | + project = shortcuts.get_project_or_404(request, project_id) |
649 | images = project.get_images() |
650 | |
651 | ami = project.get_image(image_id) |
652 | + can_modify = shortcuts.get_user_image_permissions(request.user.username, |
653 | + project_id) |
654 | |
655 | if not ami: |
656 | raise http.Http404() |
657 | - |
658 | return render_to_response('django_nova/images/index.html', { |
659 | 'form': forms.LaunchInstanceForm(project), |
660 | 'update_form': forms.UpdateImageForm(ami), |
661 | @@ -123,14 +124,14 @@ |
662 | 'images': images, |
663 | 'image_lists': _image_lists(images, project_id), |
664 | 'ami': ami, |
665 | - 'can_modify': get_user_image_permissions(request.user.username, project_id), |
666 | + 'can_modify': can_modify, |
667 | }, context_instance = template.RequestContext(request)) |
668 | |
669 | |
670 | @login_required |
671 | @handle_nova_error |
672 | def remove(request, project_id, image_id): |
673 | - project = get_project_or_404(request, project_id) |
674 | + project = shortcuts.get_project_or_404(request, project_id) |
675 | |
676 | if request.method == 'POST': |
677 | try: |
678 | @@ -159,34 +160,27 @@ |
679 | @login_required |
680 | @handle_nova_error |
681 | def privacy(request, project_id, image_id): |
682 | - project = get_project_or_404(request, project_id) |
683 | - conn = project.get_nova_connection() |
684 | + project = shortcuts.get_project_or_404(request, project_id) |
685 | |
686 | if request.method == 'POST': |
687 | ami = project.get_image(image_id) |
688 | |
689 | if ami.is_public: |
690 | - # TODO(devcamcar): create a wrapper in manager.ProjectManager |
691 | - # for modifying image attributes. |
692 | try: |
693 | - conn.modify_image_attribute(image_id, |
694 | - attribute='launchPermission', |
695 | - operation='remove', |
696 | - groups='all',) |
697 | - except boto.exception.EC2ResponseError, e: |
698 | + project.modify_image_attribute(image_id, |
699 | + attribute='launchPermission', |
700 | + operation='remove') |
701 | + except exceptions.NovaApiError, e: |
702 | messages.error(request, |
703 | - 'Unable to make image private: %s - %s' % |
704 | - (e.code, e.message,)) |
705 | + 'Unable to make image private: %s' % e.message) |
706 | else: |
707 | try: |
708 | - conn.modify_image_attribute(image_id, |
709 | - attribute='launchPermission', |
710 | - operation='add', |
711 | - groups='all') |
712 | - except boto.exception.EC2ResponseError, e: |
713 | + project.modify_image_attribute(image_id, |
714 | + attribute='launchPermission', |
715 | + operation='add') |
716 | + except exceptions.NovaApiError, e: |
717 | messages.error(request, |
718 | - 'Unable to make image public: %s - %s' % |
719 | - (e.code, e.message,)) |
720 | + 'Unable to make image public: %s' % e.message) |
721 | |
722 | return redirect('nova_images_detail', project_id, image_id) |
723 | |
724 | @@ -194,7 +188,7 @@ |
725 | @login_required |
726 | @handle_nova_error |
727 | def update(request, project_id, image_id): |
728 | - project = get_project_or_404(request, project_id) |
729 | + project = shortcuts.get_project_or_404(request, project_id) |
730 | ami = project.get_image(image_id) |
731 | |
732 | if request.method == 'POST': |
733 | @@ -221,7 +215,6 @@ |
734 | 'form': form, |
735 | 'region': project.region, |
736 | 'project': project, |
737 | - 'project_list': project_list, |
738 | 'ami': ami, |
739 | }, context_instance = template.RequestContext(request)) |
740 | else: |
741 | |
742 | === modified file 'src/django_nova/views/instances.py' |
743 | --- src/django_nova/views/instances.py 2011-01-18 23:07:26 +0000 |
744 | +++ src/django_nova/views/instances.py 2011-01-25 23:54:53 +0000 |
745 | @@ -27,14 +27,14 @@ |
746 | from django.shortcuts import redirect, render_to_response |
747 | from django_nova import exceptions |
748 | from django_nova import forms as nova_forms |
749 | +from django_nova import shortcuts |
750 | from django_nova.exceptions import handle_nova_error |
751 | -from django_nova.shortcuts import get_project_or_404 |
752 | |
753 | |
754 | @login_required |
755 | @handle_nova_error |
756 | def index(request, project_id): |
757 | - project = get_project_or_404(request, project_id) |
758 | + project = shortcuts.get_project_or_404(request, project_id) |
759 | instances = sorted(project.get_instances(), key=lambda k: k.public_dns_name) |
760 | |
761 | return render_to_response('django_nova/instances/index.html', { |
762 | @@ -48,7 +48,7 @@ |
763 | @login_required |
764 | @handle_nova_error |
765 | def detail(request, project_id, instance_id): |
766 | - project = get_project_or_404(request, project_id) |
767 | + project = shortcuts.get_project_or_404(request, project_id) |
768 | instance = project.get_instance(instance_id) |
769 | instances = sorted(project.get_instances(), key=lambda k: k.public_dns_name) |
770 | |
771 | @@ -68,7 +68,7 @@ |
772 | @login_required |
773 | @handle_nova_error |
774 | def performance(request, project_id, instance_id): |
775 | - project = get_project_or_404(request, project_id) |
776 | + project = shortcuts.get_project_or_404(request, project_id) |
777 | instance = project.get_instance(instance_id) |
778 | |
779 | if not instance: |
780 | @@ -88,7 +88,7 @@ |
781 | if not request.user.is_authenticated(): |
782 | return http.HttpResponseForbidden() |
783 | |
784 | - project = get_project_or_404(request, project_id) |
785 | + project = shortcuts.get_project_or_404(request, project_id) |
786 | instances = sorted(project.get_instances(), key=lambda k: k.public_dns_name) |
787 | |
788 | return render_to_response('django_nova/instances/_instances_list.html', { |
789 | @@ -103,7 +103,7 @@ |
790 | if not request.user.is_authenticated(): |
791 | return http.HttpResponseForbidden() |
792 | |
793 | - project = get_project_or_404(request, project_id) |
794 | + project = shortcuts.get_project_or_404(request, project_id) |
795 | instance = project.get_instance(instance_id) |
796 | instances = sorted(project.get_instances(), key=lambda k: k.public_dns_name) |
797 | |
798 | @@ -117,7 +117,7 @@ |
799 | @login_required |
800 | @handle_nova_error |
801 | def terminate(request, project_id): |
802 | - project = get_project_or_404(request, project_id) |
803 | + project = shortcuts.get_project_or_404(request, project_id) |
804 | |
805 | if request.method == 'POST': |
806 | instance_id = request.POST['instance_id'] |
807 | @@ -138,7 +138,7 @@ |
808 | @login_required |
809 | @handle_nova_error |
810 | def console(request, project_id, instance_id): |
811 | - project = get_project_or_404(request, project_id) |
812 | + project = shortcuts.get_project_or_404(request, project_id) |
813 | conn = project.get_nova_connection() |
814 | console = conn.get_console_output(instance_id) |
815 | response = http.HttpResponse(mimetype='text/plain') |
816 | @@ -151,7 +151,7 @@ |
817 | @login_required |
818 | @handle_nova_error |
819 | def graph(request, project_id, instance_id, graph_name): |
820 | - project = get_project_or_404(request, project_id) |
821 | + project = shortcuts.get_project_or_404(request, project_id) |
822 | graph = project.get_instance_graph(instance_id, graph_name) |
823 | |
824 | if graph is None: |
825 | @@ -166,10 +166,10 @@ |
826 | @login_required |
827 | @handle_nova_error |
828 | def update(request, project_id, instance_id): |
829 | - project = get_project_or_404(request, project_id) |
830 | + project = shortcuts.get_project_or_404(request, project_id) |
831 | instance = project.get_instance(instance_id) |
832 | |
833 | - if instance is None: |
834 | + if not instance: |
835 | raise http.Http404() |
836 | |
837 | if request.method == 'POST': |
838 | |
839 | === modified file 'src/django_nova/views/keypairs.py' |
840 | --- src/django_nova/views/keypairs.py 2011-01-18 23:07:26 +0000 |
841 | +++ src/django_nova/views/keypairs.py 2011-01-25 23:54:53 +0000 |
842 | @@ -27,14 +27,14 @@ |
843 | from django.shortcuts import redirect, render_to_response |
844 | from django_nova import exceptions |
845 | from django_nova import forms |
846 | +from django_nova import shortcuts |
847 | from django_nova.exceptions import handle_nova_error |
848 | -from django_nova.shortcuts import get_project_or_404 |
849 | |
850 | |
851 | @login_required |
852 | @handle_nova_error |
853 | def index(request, project_id, download_key=None): |
854 | - project = get_project_or_404(request, project_id) |
855 | + project = shortcuts.get_project_or_404(request, project_id) |
856 | keypairs = project.get_key_pairs() |
857 | |
858 | return render_to_response('django_nova/keypairs/index.html', { |
859 | @@ -48,7 +48,7 @@ |
860 | @login_required |
861 | @handle_nova_error |
862 | def add(request, project_id): |
863 | - project = get_project_or_404(request, project_id) |
864 | + project = shortcuts.get_project_or_404(request, project_id) |
865 | |
866 | if request.method == 'POST': |
867 | form = forms.CreateKeyPairForm(project, request.POST) |
868 | @@ -87,7 +87,7 @@ |
869 | @login_required |
870 | @handle_nova_error |
871 | def delete(request, project_id): |
872 | - project = get_project_or_404(request, project_id) |
873 | + project = shortcuts.get_project_or_404(request, project_id) |
874 | |
875 | if request.method == 'POST': |
876 | key_name = request.POST['key_name'] |
877 | @@ -108,7 +108,7 @@ |
878 | @handle_nova_error |
879 | def download(request, project_id, key_name): |
880 | # Ensure the project exists. |
881 | - get_project_or_404(request, project_id) |
882 | + shortcuts.get_project_or_404(request, project_id) |
883 | |
884 | try: |
885 | material = request.session.pop('key.%s' % key_name) |
approve