Merge lp:~devcamcar/django-nova/improve_unittests into lp:django-nova

Proposed by Devin Carlen
Status: Merged
Approved by: Devin Carlen
Approved revision: 21
Merged at revision: 16
Proposed branch: lp:~devcamcar/django-nova/improve_unittests
Merge into: lp:django-nova
Diff against target: 615 lines (+427/-29)
11 files modified
src/django_nova/tests/urls.py (+5/-1)
src/django_nova/tests/view_tests/__init__.py (+6/-2)
src/django_nova/tests/view_tests/base.py (+54/-15)
src/django_nova/tests/view_tests/credential_tests.py (+70/-0)
src/django_nova/tests/view_tests/image_tests.py (+22/-0)
src/django_nova/tests/view_tests/instance_tests.py (+22/-0)
src/django_nova/tests/view_tests/keypair_tests.py (+25/-3)
src/django_nova/tests/view_tests/region_tests.py (+43/-0)
src/django_nova/tests/view_tests/volume_tests.py (+170/-0)
src/django_nova/views/credentials.py (+4/-2)
src/django_nova/views/volumes.py (+6/-6)
To merge this branch: bzr merge lp:~devcamcar/django-nova/improve_unittests
Reviewer Review Type Date Requested Status
Devin Carlen Approve
Review via email: mp+49529@code.launchpad.net

Description of the change

Improved unit tests for views

To post a comment you must log in.
Revision history for this message
Devin Carlen (devcamcar) wrote :

approve

review: Approve
Revision history for this message
Jesse Andrews (anotherjesse) wrote :

u can do merge?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/django_nova/tests/urls.py'
2--- src/django_nova/tests/urls.py 2011-01-18 02:09:01 +0000
3+++ src/django_nova/tests/urls.py 2011-02-13 02:22:10 +0000
4@@ -29,4 +29,8 @@
5 url(r'^region/', include('django_nova.urls.region')),
6 url(r'^admin/projects/', include('django_nova.urls.admin_project')),
7 url(r'^admin/roles/', include('django_nova.urls.admin_roles')),
8-)
9\ No newline at end of file
10+ url(r'^credentials/download/(?P<auth_token>\w+)/$',
11+ 'django_nova.views.credentials.authorize_credentials',
12+ name='nova_credentials_authorize'),
13+)
14+
15
16=== modified file 'src/django_nova/tests/view_tests/__init__.py'
17--- src/django_nova/tests/view_tests/__init__.py 2011-01-21 22:38:42 +0000
18+++ src/django_nova/tests/view_tests/__init__.py 2011-02-13 02:22:10 +0000
19@@ -1,3 +1,7 @@
20+from credential_tests import *
21+from image_tests import *
22+from instance_tests import *
23 from keypair_tests import *
24-from image_tests import *
25-from instance_tests import *
26\ No newline at end of file
27+from region_tests import *
28+from volume_tests import *
29+
30
31=== modified file 'src/django_nova/tests/view_tests/base.py'
32--- src/django_nova/tests/view_tests/base.py 2011-01-22 22:27:53 +0000
33+++ src/django_nova/tests/view_tests/base.py 2011-02-13 02:22:10 +0000
34@@ -1,3 +1,25 @@
35+# vim: tabstop=4 shiftwidth=4 softtabstop=4
36+
37+# Copyright 2010 United States Government as represented by the
38+# Administrator of the National Aeronautics and Space Administration.
39+# All Rights Reserved.
40+#
41+# Licensed under the Apache License, Version 2.0 (the "License"); you may
42+# not use this file except in compliance with the License. You may obtain
43+# a copy of the License at
44+#
45+# http://www.apache.org/licenses/LICENSE-2.0
46+#
47+# Unless required by applicable law or agreed to in writing, software
48+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
49+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
50+# License for the specific language governing permissions and limitations
51+# under the License.
52+
53+"""
54+Base classes for view based unit tests.
55+"""
56+
57 import mox
58
59 from django import test
60@@ -13,19 +35,36 @@
61 TEST_REGION = 'test'
62
63
64-class BaseProjectViewTests(test.TestCase):
65+class BaseViewTests(test.TestCase):
66 def setUp(self):
67- project = adminclient.ProjectInfo()
68- project.projectname = TEST_PROJECT
69- project.projectManagerId = TEST_USER
70-
71 self.mox = mox.Mox()
72- self.user = auth_models.User.objects.create_user(TEST_USER,
73+
74+ def tearDown(self):
75+ self.mox.UnsetStubs()
76+
77+ def assertRedirectsNoFollow(self, response, expected_url):
78+ self.assertEqual(response._headers['location'],
79+ ('Location', settings.TESTSERVER + expected_url))
80+ self.assertEqual(response.status_code, 302)
81+
82+ def authenticateTestUser(self):
83+ user = auth_models.User.objects.create_user(TEST_USER,
84 'test@test.com',
85 password='test')
86 login = self.client.login(username=TEST_USER, password='test')
87 self.failUnless(login, 'Unable to login')
88-
89+ return user
90+
91+
92+class BaseProjectViewTests(BaseViewTests):
93+ def setUp(self):
94+ super(BaseProjectViewTests, self).setUp()
95+
96+ project = adminclient.ProjectInfo()
97+ project.projectname = TEST_PROJECT
98+ project.projectManagerId = TEST_USER
99+
100+ self.user = self.authenticateTestUser()
101 self.region = adminclient.RegionInfo(name=TEST_REGION,
102 endpoint='http://test:8773/')
103 self.project = manager.ProjectManager(self.user.username,
104@@ -35,17 +74,17 @@
105 shortcuts.get_project_or_404(mox.IgnoreArg(),
106 'test').AndReturn(self.project)
107
108- def tearDown(self):
109- self.mox.UnsetStubs()
110-
111- def assertRedirectsNoFollow(self, response, expected_url):
112- self.assertEqual(response._headers['location'],
113- ('Location', settings.TESTSERVER + expected_url))
114- self.assertEqual(response.status_code, 302)
115-
116 def create_key_pair_choices(self, key_names):
117 return [(k, k) for k in key_names]
118
119 def create_instance_type_choices(self):
120 return [('m1.medium', 'm1.medium'),
121 ('m1.large', 'm1.large')]
122+
123+ def create_instance_choices(self, instance_ids):
124+ return [(id, id) for id in instance_ids]
125+
126+ def create_available_volume_choices(self, volumes):
127+ return [(v.id, '%s %s - %dGB' % (v.id, v.displayName, v.size)) \
128+ for v in volumes]
129+
130
131=== added file 'src/django_nova/tests/view_tests/credential_tests.py'
132--- src/django_nova/tests/view_tests/credential_tests.py 1970-01-01 00:00:00 +0000
133+++ src/django_nova/tests/view_tests/credential_tests.py 2011-02-13 02:22:10 +0000
134@@ -0,0 +1,70 @@
135+# vim: tabstop=4 shiftwidth=4 softtabstop=4
136+
137+# Copyright 2010 United States Government as represented by the
138+# Administrator of the National Aeronautics and Space Administration.
139+# All Rights Reserved.
140+#
141+# Licensed under the Apache License, Version 2.0 (the "License"); you may
142+# not use this file except in compliance with the License. You may obtain
143+# a copy of the License at
144+#
145+# http://www.apache.org/licenses/LICENSE-2.0
146+#
147+# Unless required by applicable law or agreed to in writing, software
148+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
149+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
150+# License for the specific language governing permissions and limitations
151+# under the License.
152+
153+"""
154+Unit tests for credential views.
155+"""
156+
157+import mox
158+from django.conf import settings
159+from django.core.urlresolvers import reverse
160+from django_nova import models
161+from django_nova.tests.view_tests.base import BaseViewTests
162+
163+
164+class CredentialViewTests(BaseViewTests):
165+ def test_download_expired_credentials(self):
166+ auth_token = 'expired'
167+ self.mox.StubOutWithMock(models.CredentialsAuthorization,
168+ 'get_by_token')
169+ models.CredentialsAuthorization.get_by_token(auth_token) \
170+ .AndReturn(None)
171+ self.mox.ReplayAll()
172+
173+ res = self.client.get(reverse('nova_credentials_authorize',
174+ args=[auth_token]))
175+ self.assertTemplateUsed(res, 'django_nova/credentials/expired.html')
176+
177+ self.mox.VerifyAll()
178+
179+ def test_download_good_credentials(self):
180+ auth_token = 'good'
181+
182+ creds = models.CredentialsAuthorization()
183+ creds.username = 'test'
184+ creds.project = 'test'
185+ creds.auth_token = auth_token
186+
187+ self.mox.StubOutWithMock(models.CredentialsAuthorization,
188+ 'get_by_token')
189+ self.mox.StubOutWithMock(creds, 'get_zip')
190+ models.CredentialsAuthorization.get_by_token(auth_token) \
191+ .AndReturn(creds)
192+ creds.get_zip().AndReturn('zip')
193+
194+ self.mox.ReplayAll()
195+
196+ res = self.client.get(reverse('nova_credentials_authorize',
197+ args=[auth_token]))
198+ self.assertEqual(res.status_code, 200)
199+ self.assertEqual(res['Content-Disposition'],
200+ 'attachment; filename=%s-test-test-x509.zip' %
201+ settings.SITE_NAME)
202+ self.assertContains(res, 'zip')
203+
204+ self.mox.VerifyAll()
205
206=== modified file 'src/django_nova/tests/view_tests/image_tests.py'
207--- src/django_nova/tests/view_tests/image_tests.py 2011-01-25 23:51:20 +0000
208+++ src/django_nova/tests/view_tests/image_tests.py 2011-02-13 02:22:10 +0000
209@@ -1,3 +1,25 @@
210+# vim: tabstop=4 shiftwidth=4 softtabstop=4
211+
212+# Copyright 2010 United States Government as represented by the
213+# Administrator of the National Aeronautics and Space Administration.
214+# All Rights Reserved.
215+#
216+# Licensed under the Apache License, Version 2.0 (the "License"); you may
217+# not use this file except in compliance with the License. You may obtain
218+# a copy of the License at
219+#
220+# http://www.apache.org/licenses/LICENSE-2.0
221+#
222+# Unless required by applicable law or agreed to in writing, software
223+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
224+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
225+# License for the specific language governing permissions and limitations
226+# under the License.
227+
228+"""
229+Unit tests for image views.
230+"""
231+
232 import boto.ec2.image
233 import boto.ec2.instance
234 import mox
235
236=== modified file 'src/django_nova/tests/view_tests/instance_tests.py'
237--- src/django_nova/tests/view_tests/instance_tests.py 2011-01-22 01:04:51 +0000
238+++ src/django_nova/tests/view_tests/instance_tests.py 2011-02-13 02:22:10 +0000
239@@ -1,3 +1,25 @@
240+# vim: tabstop=4 shiftwidth=4 softtabstop=4
241+
242+# Copyright 2010 United States Government as represented by the
243+# Administrator of the National Aeronautics and Space Administration.
244+# All Rights Reserved.
245+#
246+# Licensed under the Apache License, Version 2.0 (the "License"); you may
247+# not use this file except in compliance with the License. You may obtain
248+# a copy of the License at
249+#
250+# http://www.apache.org/licenses/LICENSE-2.0
251+#
252+# Unless required by applicable law or agreed to in writing, software
253+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
254+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
255+# License for the specific language governing permissions and limitations
256+# under the License.
257+
258+"""
259+Unit tests for instance views.
260+"""
261+
262 import boto.ec2.instance
263 import mox
264
265
266=== modified file 'src/django_nova/tests/view_tests/keypair_tests.py'
267--- src/django_nova/tests/view_tests/keypair_tests.py 2011-01-22 01:04:51 +0000
268+++ src/django_nova/tests/view_tests/keypair_tests.py 2011-02-13 02:22:10 +0000
269@@ -1,8 +1,31 @@
270+# vim: tabstop=4 shiftwidth=4 softtabstop=4
271+
272+# Copyright 2010 United States Government as represented by the
273+# Administrator of the National Aeronautics and Space Administration.
274+# All Rights Reserved.
275+#
276+# Licensed under the Apache License, Version 2.0 (the "License"); you may
277+# not use this file except in compliance with the License. You may obtain
278+# a copy of the License at
279+#
280+# http://www.apache.org/licenses/LICENSE-2.0
281+#
282+# Unless required by applicable law or agreed to in writing, software
283+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
284+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
285+# License for the specific language governing permissions and limitations
286+# under the License.
287+
288+"""
289+Unit tests for key pair views.
290+"""
291+
292 import boto.ec2.keypair
293 import mox
294
295 from django.core.urlresolvers import reverse
296-from django_nova.tests.view_tests.base import BaseProjectViewTests, TEST_PROJECT
297+from django_nova.tests.view_tests.base import (BaseProjectViewTests,
298+ TEST_PROJECT)
299
300
301 TEST_KEY = 'test_key'
302@@ -36,8 +59,7 @@
303
304 url = reverse('nova_keypairs_add', args=[TEST_PROJECT])
305 data = {'js': '0', 'name': key.name}
306- res = self.client.post(url,
307- data)
308+ res = self.client.post(url, data)
309 self.assertEqual(res.status_code, 200)
310 self.assertEqual(res['Content-Type'], 'application/binary')
311
312
313=== added file 'src/django_nova/tests/view_tests/region_tests.py'
314--- src/django_nova/tests/view_tests/region_tests.py 1970-01-01 00:00:00 +0000
315+++ src/django_nova/tests/view_tests/region_tests.py 2011-02-13 02:22:10 +0000
316@@ -0,0 +1,43 @@
317+# vim: tabstop=4 shiftwidth=4 softtabstop=4
318+
319+# Copyright 2010 United States Government as represented by the
320+# Administrator of the National Aeronautics and Space Administration.
321+# All Rights Reserved.
322+#
323+# Licensed under the Apache License, Version 2.0 (the "License"); you may
324+# not use this file except in compliance with the License. You may obtain
325+# a copy of the License at
326+#
327+# http://www.apache.org/licenses/LICENSE-2.0
328+#
329+# Unless required by applicable law or agreed to in writing, software
330+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
331+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
332+# License for the specific language governing permissions and limitations
333+# under the License.
334+
335+"""
336+Unit tests for region views.
337+"""
338+
339+from django.core.urlresolvers import reverse
340+from django_nova.tests.view_tests.base import BaseViewTests
341+from django_nova import shortcuts
342+
343+
344+TEST_REGION = 'one'
345+
346+
347+class RegionViewTests(BaseViewTests):
348+ def test_change(self):
349+ self.authenticateTestUser()
350+ session = self.client.session
351+ session['region'] = 'two'
352+ session.save()
353+
354+ data = {'redirect_url': '/',
355+ 'region': TEST_REGION}
356+ res = self.client.post(reverse('region_change'), data)
357+ self.assertEqual(self.client.session['region'], TEST_REGION)
358+ self.assertRedirectsNoFollow(res, '/')
359+
360
361=== added file 'src/django_nova/tests/view_tests/volume_tests.py'
362--- src/django_nova/tests/view_tests/volume_tests.py 1970-01-01 00:00:00 +0000
363+++ src/django_nova/tests/view_tests/volume_tests.py 2011-02-13 02:22:10 +0000
364@@ -0,0 +1,170 @@
365+# vim: tabstop=4 shiftwidth=4 softtabstop=4
366+
367+# Copyright 2010 United States Government as represented by the
368+# Administrator of the National Aeronautics and Space Administration.
369+# All Rights Reserved.
370+#
371+# Licensed under the Apache License, Version 2.0 (the "License"); you may
372+# not use this file except in compliance with the License. You may obtain
373+# a copy of the License at
374+#
375+# http://www.apache.org/licenses/LICENSE-2.0
376+#
377+# Unless required by applicable law or agreed to in writing, software
378+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
379+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
380+# License for the specific language governing permissions and limitations
381+# under the License.
382+
383+"""
384+Unit tests for volume views.
385+"""
386+
387+import boto.ec2.volume
388+import mox
389+
390+from django.core.urlresolvers import reverse
391+from django_nova import forms
392+from django_nova.tests.view_tests.base import (BaseProjectViewTests,
393+ TEST_PROJECT)
394+
395+
396+TEST_VOLUME = 'vol-0000001'
397+
398+
399+class VolumeTests(BaseProjectViewTests):
400+ def test_index(self):
401+ instance_id = 'i-abcdefgh'
402+
403+ volume = boto.ec2.volume.Volume()
404+ volume.id = TEST_VOLUME
405+ volume.displayName = TEST_VOLUME
406+ volume.size = 1
407+
408+ self.mox.StubOutWithMock(self.project, 'get_volumes')
409+ self.mox.StubOutWithMock(forms, 'get_available_volume_choices')
410+ self.mox.StubOutWithMock(forms, 'get_instance_choices')
411+ self.project.get_volumes().AndReturn([])
412+ forms.get_available_volume_choices(mox.IgnoreArg()).AndReturn(
413+ self.create_available_volume_choices([volume]))
414+ forms.get_instance_choices(mox.IgnoreArg()).AndReturn(
415+ self.create_instance_choices([instance_id]))
416+
417+ self.mox.ReplayAll()
418+
419+ response = self.client.get(reverse('nova_volumes',
420+ args=[TEST_PROJECT]))
421+ self.assertEqual(response.status_code, 200)
422+ self.assertTemplateUsed(response, 'django_nova/volumes/index.html')
423+ self.assertEqual(len(response.context['volumes']), 0)
424+
425+ self.mox.VerifyAll()
426+
427+ def test_add_get(self):
428+ self.mox.ReplayAll()
429+
430+ res = self.client.get(reverse('nova_volumes_add', args=[TEST_PROJECT]))
431+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
432+ args=[TEST_PROJECT]))
433+ self.mox.VerifyAll()
434+
435+ def test_add_post(self):
436+ vol = boto.ec2.volume.Volume()
437+ vol.name = TEST_VOLUME
438+ vol.displayName = TEST_VOLUME
439+ vol.size = 1
440+
441+ self.mox.StubOutWithMock(self.project, 'create_volume')
442+ self.project.create_volume(vol.size, vol.name, vol.name).AndReturn(vol)
443+
444+ self.mox.ReplayAll()
445+
446+ url = reverse('nova_volumes_add', args=[TEST_PROJECT])
447+ data = {'size': '1',
448+ 'nickname': TEST_VOLUME,
449+ 'description': TEST_VOLUME}
450+ res = self.client.post(url, data)
451+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
452+ args=[TEST_PROJECT]))
453+ self.mox.VerifyAll()
454+
455+ def test_delete_get(self):
456+ self.mox.ReplayAll()
457+
458+ res = self.client.get(reverse('nova_volumes_delete',
459+ args=[TEST_PROJECT, TEST_VOLUME]))
460+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
461+ args=[TEST_PROJECT]))
462+ self.mox.VerifyAll()
463+
464+ def test_delete_post(self):
465+ self.mox.StubOutWithMock(self.project, 'delete_volume')
466+ self.project.delete_volume(TEST_VOLUME).AndReturn(True)
467+
468+ self.mox.ReplayAll()
469+
470+ res = self.client.post(reverse('nova_volumes_delete',
471+ args=[TEST_PROJECT, TEST_VOLUME]))
472+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
473+ args=[TEST_PROJECT]))
474+ self.mox.VerifyAll()
475+
476+ def test_attach_get(self):
477+ self.mox.ReplayAll()
478+
479+ res = self.client.get(reverse('nova_volumes_attach',
480+ args=[TEST_PROJECT]))
481+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
482+ args=[TEST_PROJECT]))
483+ self.mox.VerifyAll()
484+
485+ def test_attach_post(self):
486+ volume = boto.ec2.volume.Volume()
487+ volume.id = TEST_VOLUME
488+ volume.displayName = TEST_VOLUME
489+ volume.size = 1
490+
491+ instance_id = 'i-abcdefgh'
492+ device = '/dev/vdb'
493+
494+ self.mox.StubOutWithMock(self.project, 'attach_volume')
495+ self.mox.StubOutWithMock(forms, 'get_available_volume_choices')
496+ self.mox.StubOutWithMock(forms, 'get_instance_choices')
497+ self.project.attach_volume(TEST_VOLUME, instance_id, device) \
498+ .AndReturn(True)
499+ forms.get_available_volume_choices(mox.IgnoreArg()).AndReturn(
500+ self.create_available_volume_choices([volume]))
501+ forms.get_instance_choices(mox.IgnoreArg()).AndReturn(
502+ self.create_instance_choices([instance_id]))
503+
504+ self.mox.ReplayAll()
505+
506+ url = reverse('nova_volumes_attach', args=[TEST_PROJECT])
507+ data = {'volume': TEST_VOLUME,
508+ 'instance': instance_id,
509+ 'device': device}
510+ res = self.client.post(url, data)
511+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
512+ args=[TEST_PROJECT]))
513+ self.mox.VerifyAll()
514+
515+ def test_detach_get(self):
516+ self.mox.ReplayAll()
517+
518+ res = self.client.get(reverse('nova_volumes_detach',
519+ args=[TEST_PROJECT, TEST_VOLUME]))
520+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
521+ args=[TEST_PROJECT]))
522+ self.mox.VerifyAll()
523+
524+ def test_detach_post(self):
525+ self.mox.StubOutWithMock(self.project, 'detach_volume')
526+ self.project.detach_volume(TEST_VOLUME).AndReturn(True)
527+
528+ self.mox.ReplayAll()
529+
530+ res = self.client.post(reverse('nova_volumes_detach',
531+ args=[TEST_PROJECT, TEST_VOLUME]))
532+ self.assertRedirectsNoFollow(res, reverse('nova_volumes',
533+ args=[TEST_PROJECT]))
534+ self.mox.VerifyAll()
535
536=== modified file 'src/django_nova/views/credentials.py'
537--- src/django_nova/views/credentials.py 2011-01-31 20:08:02 +0000
538+++ src/django_nova/views/credentials.py 2011-02-13 02:22:10 +0000
539@@ -17,7 +17,8 @@
540 # under the License.
541
542 """
543-Views for downloading X509 credentials.
544+Views for downloading X509 credentials. Useful when using an invitation
545+style system for configuring first time users.
546 """
547
548 from django import http
549@@ -26,7 +27,8 @@
550 from django_nova import models
551
552
553-def download_credentials(request, auth_token):
554+def authorize_credentials(request, auth_token):
555+ """Sends X509 credentials to user if their auth token is valid."""
556 auth_token = auth_token.lower()
557 credentials = models.CredentialsAuthorization.get_by_token(auth_token)
558
559
560=== modified file 'src/django_nova/views/volumes.py'
561--- src/django_nova/views/volumes.py 2011-01-25 23:16:49 +0000
562+++ src/django_nova/views/volumes.py 2011-02-13 02:22:10 +0000
563@@ -26,14 +26,14 @@
564 from django.shortcuts import redirect, render_to_response
565 from django_nova import exceptions
566 from django_nova import forms
567+from django_nova import shortcuts
568 from django_nova.exceptions import handle_nova_error
569-from django_nova.shortcuts import get_project_or_404
570
571
572 @login_required
573 @handle_nova_error
574 def index(request, project_id):
575- project = get_project_or_404(request, project_id)
576+ project = shortcuts.get_project_or_404(request, project_id)
577 volumes = project.get_volumes()
578
579 return render_to_response('django_nova/volumes/index.html', {
580@@ -48,7 +48,7 @@
581 @login_required
582 @handle_nova_error
583 def add(request, project_id):
584- project = get_project_or_404(request, project_id)
585+ project = shortcuts.get_project_or_404(request, project_id)
586
587 if request.method == 'POST':
588 form = forms.CreateVolumeForm(request.POST)
589@@ -81,7 +81,7 @@
590 @login_required
591 @handle_nova_error
592 def delete(request, project_id, volume_id):
593- project = get_project_or_404(request, project_id)
594+ project = shortcuts.get_project_or_404(request, project_id)
595
596 if request.method == 'POST':
597 try:
598@@ -100,7 +100,7 @@
599 @login_required
600 @handle_nova_error
601 def attach(request, project_id):
602- project = get_project_or_404(request, project_id)
603+ project = shortcuts.get_project_or_404(request, project_id)
604
605 if request.method == 'POST':
606 form = forms.AttachVolumeForm(project, request.POST)
607@@ -135,7 +135,7 @@
608 @login_required
609 @handle_nova_error
610 def detach(request, project_id, volume_id):
611- project = get_project_or_404(request, project_id)
612+ project = shortcuts.get_project_or_404(request, project_id)
613
614 if request.method == 'POST':
615 try:

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: