Skip to content

Commit 3ba167f

Browse files
committed
add tests, improve tests
1 parent 46d0eba commit 3ba167f

File tree

4 files changed

+160
-23
lines changed

4 files changed

+160
-23
lines changed

coldfront/core/allocation/tests/test_views.py

Lines changed: 133 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,25 @@
33
# SPDX-License-Identifier: AGPL-3.0-or-later
44

55
import logging
6+
from datetime import date
67
from http import HTTPStatus
78

9+
from dateutil.relativedelta import relativedelta
810
from django.conf import settings
11+
from django.contrib.auth.models import User
912
from django.test import TestCase, override_settings
1013
from django.urls import reverse
1114

1215
from 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
)
1626
from coldfront.core.test_helpers import utils
1727
from coldfront.core.test_helpers.factories import (
@@ -28,10 +38,12 @@
2838
ResourceFactory,
2939
UserFactory,
3040
)
41+
from coldfront.core.utils.common import import_from_settings
3142

3243
logging.disable(logging.CRITICAL)
3344

3445
BACKEND = "django.contrib.auth.backends.ModelBackend"
46+
ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS = import_from_settings("ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS")
3547

3648

3749
class 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):
134146
class 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

157248
class 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

coldfront/core/allocation/views.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,12 @@ def get_queryset(self):
16951695

16961696

16971697
class AllocationChangeDetailView(LoginRequiredMixin, UserPassesTestMixin, FormView):
1698+
"""
1699+
Allows a superuser to approve or deny an AllocationChangeRequest
1700+
Allows a superuser to update the end_date_extension or notes of an AllocationChangeRequest
1701+
See AllocationAttributeEditView for updating an AllocationChangeRequest's AllocationAttributeChangeRequest
1702+
"""
1703+
16981704
formset_class = AllocationAttributeUpdateForm
16991705
template_name = "allocation/allocation_change_detail.html"
17001706

@@ -1711,6 +1717,7 @@ def test_func(self):
17111717
return False
17121718

17131719
def get_allocation_attributes_to_change(self, allocation_change_obj):
1720+
"""Find all allocation change requests for the specified allocation, format as list of dicts"""
17141721
attributes_to_change = allocation_change_obj.allocationattributechangerequest_set.all()
17151722

17161723
attributes_to_change = [
@@ -1955,6 +1962,8 @@ def get_context_data(self, **kwargs):
19551962

19561963

19571964
class AllocationChangeView(LoginRequiredMixin, UserPassesTestMixin, FormView):
1965+
"""Allows a user with manager permissions to create an allocation change request"""
1966+
19581967
formset_class = AllocationAttributeChangeForm
19591968
template_name = "allocation/allocation_change.html"
19601969

@@ -2003,6 +2012,7 @@ def dispatch(self, request, *args, **kwargs):
20032012
return super().dispatch(request, *args, **kwargs)
20042013

20052014
def get_allocation_attributes_to_change(self, allocation_obj):
2015+
"""Find all changeable attributes for the specified allocation, format as list of dicts"""
20062016
attributes_to_change = allocation_obj.allocationattribute_set.filter(
20072017
allocation_attribute_type__is_changeable=True
20082018
)

coldfront/core/portal/tests/test_views.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from django.test import TestCase
88

9+
from coldfront.core.test_helpers import utils
10+
911
logging.disable(logging.CRITICAL)
1012

1113

@@ -29,7 +31,7 @@ def setUpTestData(cls):
2931

3032
def test_centersummary_renders(self):
3133
response = self.client.get(self.url)
32-
self.assertEqual(response.status_code, 200)
34+
utils.assert_response_success(self, response)
3335
self.assertContains(response, "Active Allocations and Users")
3436
self.assertContains(response, "Resources and Allocations Summary")
3537
self.assertNotContains(response, "We're having a bit of system trouble at the moment. Please check back soon!")

coldfront/core/test_helpers/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#
33
# SPDX-License-Identifier: AGPL-3.0-or-later
44

5+
from django.contrib import messages
6+
from django.test import TestCase
7+
from requests import Response
8+
59
"""utility functions for unit and integration testing"""
610

711

@@ -89,3 +93,13 @@ def test_user_can_access(test_case, user, page):
8993
"""
9094
response = login_and_get_page(test_case.client, user, page)
9195
test_case.assertEqual(response.status_code, 200)
96+
97+
98+
def assert_response_success(test_case: TestCase, response: Response):
99+
"""Confirm that response status is 200 and response contains no error messages"""
100+
test_case.assertEqual(response.status_code, 200)
101+
errors = []
102+
for message in response.context["messages"]:
103+
if message.level >= messages.ERROR:
104+
errors.append(message.message)
105+
test_case.assertEqual([], errors)

0 commit comments

Comments
 (0)