33# SPDX-License-Identifier: AGPL-3.0-or-later
44
55import logging
6+ from datetime import date
67from http import HTTPStatus
78
9+ from dateutil .relativedelta import relativedelta
810from django .conf import settings
11+ from django .contrib .auth .models import User
912from django .test import TestCase , override_settings
1013from django .urls import reverse
1114
1215from coldfront .core .allocation .models import (
16+ Allocation ,
17+ AllocationAttribute ,
18+ AllocationAttributeChangeRequest ,
1319 AllocationChangeRequest ,
14- AllocationChangeStatusChoice ,
20+ )
21+ from coldfront .core .project .models import (
22+ Project ,
23+ ProjectUser ,
24+ ProjectUserRoleChoice ,
1525)
1626from coldfront .core .test_helpers import utils
1727from coldfront .core .test_helpers .factories import (
2838 ResourceFactory ,
2939 UserFactory ,
3040)
41+ from coldfront .core .utils .common import import_from_settings
3142
3243logging .disable (logging .CRITICAL )
3344
3445BACKEND = "django.contrib.auth.backends.ModelBackend"
46+ ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS = import_from_settings ("ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS" )
3547
3648
3749class AllocationViewBaseTest (TestCase ):
@@ -40,28 +52,28 @@ class AllocationViewBaseTest(TestCase):
4052 @classmethod
4153 def setUpTestData (cls ):
4254 """Test Data setup for all allocation view tests."""
43- pi_user = UserFactory ()
55+ pi_user : User = UserFactory ()
4456 pi_user .userprofile .is_pi = True
4557 AllocationStatusChoiceFactory (name = "New" )
46- cls .project = ProjectFactory (pi = pi_user , status = ProjectStatusChoiceFactory (name = "Active" ))
47- cls .allocation = AllocationFactory (project = cls .project )
58+ cls .project : Project = ProjectFactory (pi = pi_user , status = ProjectStatusChoiceFactory (name = "Active" ))
59+ cls .allocation : Allocation = AllocationFactory (project = cls .project , end_date = date . today () )
4860 cls .allocation .resources .add (ResourceFactory (name = "holylfs07/tier1" ))
4961 # create allocation user that belongs to project
5062 allocation_user = AllocationUserFactory (allocation = cls .allocation )
51- cls .allocation_user = allocation_user .user
63+ cls .allocation_user : User = allocation_user .user
5264 ProjectUserFactory (project = cls .project , user = allocation_user .user )
5365 # create project user that isn't an allocationuser
54- proj_nonallocation_user = ProjectUserFactory ()
66+ proj_nonallocation_user : ProjectUser = ProjectUserFactory ()
5567 cls .proj_nonallocation_user = proj_nonallocation_user .user
56- cls .admin_user = UserFactory (is_staff = True , is_superuser = True )
57- manager_role = ProjectUserRoleChoiceFactory (name = "Manager" )
68+ cls .admin_user : User = UserFactory (is_staff = True , is_superuser = True )
69+ manager_role : ProjectUserRoleChoice = ProjectUserRoleChoiceFactory (name = "Manager" )
5870 ProjectUserFactory (user = pi_user , project = cls .project , role = manager_role )
5971 cls .pi_user = pi_user
6072 # make a quota TB allocation attribute
61- AllocationAttributeFactory (
73+ cls . quota_attribute : AllocationAttribute = AllocationAttributeFactory (
6274 allocation = cls .allocation ,
6375 value = 100 ,
64- allocation_attribute_type = AllocationAttributeTypeFactory (name = "Storage Quota (TB)" ),
76+ allocation_attribute_type = AllocationAttributeTypeFactory (name = "Storage Quota (TB)" , is_changeable = True ),
6577 )
6678
6779 def allocation_access_tstbase (self , url ):
@@ -134,24 +146,103 @@ def test_allocation_list_search_admin(self):
134146class AllocationChangeDetailViewTest (AllocationViewBaseTest ):
135147 """Tests for AllocationChangeDetailView"""
136148
149+ # TODO this view can also be used to modify alloc_change_req.notes
150+ # TODO this view does different things for action=update depending if status is Pending or not
151+
137152 def setUp (self ):
138153 """create an AllocationChangeRequest to test"""
139154 self .client .force_login (self .admin_user , backend = BACKEND )
140- AllocationChangeRequestFactory (id = 2 , allocation = self .allocation )
155+ AllocationChangeRequestFactory (id = 2 , allocation = self .allocation ) # view, deny
156+ AllocationChangeRequestFactory (
157+ id = 3 , allocation = self .allocation , end_date_extension = ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS [0 ]
158+ ) # approve end date extension
159+ req4 = AllocationChangeRequestFactory (id = 4 , allocation = self .allocation ) # approve attribute change
160+ AllocationChangeRequestFactory (
161+ id = 5 , allocation = self .allocation , end_date_extension = ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS [0 ]
162+ ) # update end date extension
163+ AllocationAttributeChangeRequest .objects .create (
164+ allocation_change_request = req4 , allocation_attribute = self .quota_attribute , new_value = 200
165+ )
141166
142- def test_allocationchangedetailview_access (self ):
167+ def test_allocationchangedetailview_access_granted (self ):
143168 response = self .client .get (reverse ("allocation-change-detail" , kwargs = {"pk" : 2 }))
144- self .assertEqual (response .status_code , 200 )
169+ utils .assert_response_success (self , response )
170+
171+ def test_allocationchangedetailview_access_denied (self ):
172+ try :
173+ self .client .force_login (self .allocation_user )
174+ response = self .client .get (reverse ("allocation-change-detail" , kwargs = {"pk" : 2 }))
175+ self .assertEqual (response .status_code , 403 )
176+ finally :
177+ self .client .force_login (self .admin_user )
145178
146179 def test_allocationchangedetailview_post_deny (self ):
147180 """Test that posting to AllocationChangeDetailView with action=deny
148- changes the status of the AllocationChangeRequest to denied ."""
181+ changes the status of AllocationChangeRequest(pk=2) to Denied ."""
149182 param = {"action" : "deny" }
150183 response = self .client .post (reverse ("allocation-change-detail" , kwargs = {"pk" : 2 }), param , follow = True )
151- self . assertEqual ( response . status_code , 200 )
184+ utils . assert_response_success ( self , response )
152185 alloc_change_req = AllocationChangeRequest .objects .get (pk = 2 )
153- denied_status_id = AllocationChangeStatusChoice .objects .get (name = "Denied" ).pk
154- self .assertEqual (alloc_change_req .status_id , denied_status_id )
186+ self .assertEqual (alloc_change_req .status .name , "Denied" )
187+
188+ def test_allocationchangedetailview_post_approve_end_date_extension (self ):
189+ """Test that posting to AllocationChangeDetailView with action=approve
190+ changes the status of AllocationChangeRequest(pk=3) to Approved and applies the end date extension."""
191+ alloc_change_req = AllocationChangeRequest .objects .get (pk = 3 )
192+ self .allocation .refresh_from_db ()
193+ alloc_change_req .refresh_from_db ()
194+ self .assertEqual (alloc_change_req .status .name , "Pending" )
195+ expected_new_end_date = self .allocation .end_date + relativedelta (days = alloc_change_req .end_date_extension )
196+ response = self .client .post (
197+ reverse ("allocation-change-detail" , kwargs = {"pk" : 3 }),
198+ {"action" : "approve" , "end_date_extension" : alloc_change_req .end_date_extension },
199+ follow = True ,
200+ )
201+ utils .assert_response_success (self , response )
202+ self .allocation .refresh_from_db ()
203+ alloc_change_req .refresh_from_db ()
204+ self .assertEqual (alloc_change_req .status .name , "Approved" )
205+ self .assertEqual (expected_new_end_date , self .allocation .end_date )
206+
207+ def test_allocationchangedetailview_post_approve_attribute_change (self ):
208+ """Test that posting to AllocationChangeDetailView with action=approve
209+ changes the status of AllocationChangeRequest(pk=4) to Approved and updates the storage quota to 200."""
210+ alloc_change_req = AllocationChangeRequest .objects .get (pk = 4 )
211+ self .allocation .refresh_from_db ()
212+ alloc_change_req .refresh_from_db ()
213+ self .assertEqual (alloc_change_req .status .name , "Pending" )
214+ response = self .client .post (
215+ reverse ("allocation-change-detail" , kwargs = {"pk" : 4 }),
216+ {
217+ "action" : "approve" ,
218+ "attributeform-INITIAL_FORMS" : "1" ,
219+ "attributeform-TOTAL_FORMS" : "1" ,
220+ "attributeform-0-new_value" : "200" ,
221+ },
222+ follow = True ,
223+ )
224+ utils .assert_response_success (self , response )
225+ self .allocation .refresh_from_db ()
226+ alloc_change_req .refresh_from_db ()
227+ self .assertEqual (alloc_change_req .status .name , "Approved" )
228+ self .assertEqual (200 , self .allocation .get_attribute ("Storage Quota (TB)" ))
229+
230+ def test_allocationchangedetailview_post_update_end_date_extension (self ):
231+ """Test that posting to AllocationChangeDetailView with action=update
232+ does not change the status of AllocationChangeRequest(pk=5) and changes the end date extension."""
233+ alloc_change_req = AllocationChangeRequest .objects .get (pk = 5 )
234+ alloc_change_req .refresh_from_db ()
235+ self .assertEqual (alloc_change_req .status .name , "Pending" )
236+ self .assertEqual (alloc_change_req .end_date_extension , ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS [0 ])
237+ response = self .client .post (
238+ reverse ("allocation-change-detail" , kwargs = {"pk" : 5 }),
239+ {"action" : "update" , "end_date_extension" : ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS [1 ]},
240+ follow = True ,
241+ )
242+ utils .assert_response_success (self , response )
243+ alloc_change_req .refresh_from_db ()
244+ self .assertEqual (alloc_change_req .status .name , "Pending" )
245+ self .assertEqual (alloc_change_req .end_date_extension , ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS [1 ])
155246
156247
157248class AllocationChangeViewTest (AllocationViewBaseTest ):
@@ -176,15 +267,35 @@ def test_allocationchangeview_access(self):
176267 utils .test_user_can_access (self , self .pi_user , self .url ) # Manager can access
177268 utils .test_user_cannot_access (self , self .allocation_user , self .url ) # user can't access
178269
270+ def test_allocationchangeview_post_attribute_change (self ):
271+ """Test post request to change an attribute"""
272+ post_data = self .post_data .copy ()
273+ post_data .update ({"attributeform-0-pk" : self .quota_attribute .pk , "attributeform-0-new_value" : "200" })
274+ self .quota_attribute .refresh_from_db ()
275+ self .assertEqual ("100" , self .quota_attribute .value )
276+ self .assertEqual (len (AllocationAttributeChangeRequest .objects .all ()), 0 )
277+ response = self .client .post (self .url , data = post_data , follow = True )
278+ utils .assert_response_success (self , response )
279+ self .assertEqual (len (AllocationAttributeChangeRequest .objects .all ()), 1 )
280+ allocation_attribute_change_request = AllocationAttributeChangeRequest .objects .all ()[0 ]
281+ self .assertEqual (
282+ "Storage Quota (TB)" ,
283+ allocation_attribute_change_request .allocation_attribute .allocation_attribute_type .name ,
284+ )
285+ self .assertEqual ("200" , allocation_attribute_change_request .new_value )
286+
179287 def test_allocationchangeview_post_extension (self ):
180288 """Test post request to extend end date"""
181289
182- self .post_data ["end_date_extension" ] = 90
290+ post_data = self .post_data .copy ()
291+ post_data ["end_date_extension" ] = 90
183292 self .assertEqual (len (AllocationChangeRequest .objects .all ()), 0 )
184- response = self .client .post (self .url , data = self . post_data , follow = True )
185- self . assertEqual ( response . status_code , 200 )
293+ response = self .client .post (self .url , data = post_data , follow = True )
294+ utils . assert_response_success ( self , response )
186295 self .assertContains (response , "Allocation change request successfully submitted." )
187296 self .assertEqual (len (AllocationChangeRequest .objects .all ()), 1 )
297+ allocation_change_request = AllocationChangeRequest .objects .all ()[0 ]
298+ self .assertEqual (90 , allocation_change_request .end_date_extension )
188299
189300 def test_allocationchangeview_post_no_change (self ):
190301 """Post request with no change should not go through"""
@@ -310,7 +421,7 @@ def test_allocationcreateview_post(self):
310421 """Test POST to the AllocationCreateView"""
311422 self .assertEqual (len (self .project .allocation_set .all ()), 1 )
312423 response = self .client .post (self .url , data = self .post_data , follow = True )
313- self . assertEqual ( response . status_code , 200 )
424+ utils . assert_response_success ( self , response )
314425 self .assertContains (response , "Allocation requested." )
315426 self .assertEqual (len (self .project .allocation_set .all ()), 2 )
316427
@@ -319,7 +430,7 @@ def test_allocationcreateview_post_zeroquantity(self):
319430 self .post_data ["quantity" ] = "0"
320431 self .assertEqual (len (self .project .allocation_set .all ()), 1 )
321432 response = self .client .post (self .url , data = self .post_data , follow = True )
322- self . assertEqual ( response . status_code , 200 )
433+ utils . assert_response_success ( self , response )
323434 self .assertContains (response , "Allocation requested." )
324435 self .assertEqual (len (self .project .allocation_set .all ()), 2 )
325436
0 commit comments