diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 7439217a1..0e86e7764 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1156,7 +1156,7 @@ class DomainAdmin(ListHeaderAdmin): return None # Get the date we want to update to - desired_date = date.today() + relativedelta(years=1) + desired_date = self._get_current_date() + relativedelta(years=1) # Grab the current expiration date try: @@ -1164,7 +1164,7 @@ class DomainAdmin(ListHeaderAdmin): except KeyError: # if no expiration date from registry, set it to today logger.warning("current expiration date not set; setting to today") - exp_date = date.today() + exp_date = self._get_current_date() # If the expiration date is super old (2020, for example), we need to # "catch up" to the current year, so we add the difference. @@ -1178,9 +1178,10 @@ class DomainAdmin(ListHeaderAdmin): # Renew the domain. try: obj.renew_domain(length=years) + self.message_user( request, - f"Successfully extended the expiration date.", + "Successfully extended the expiration date.", ) except RegistryError as err: if err.is_connection_error(): @@ -1203,6 +1204,13 @@ class DomainAdmin(ListHeaderAdmin): return HttpResponseRedirect(".") + # Workaround for unit tests, as we cannot mock date directly. + # it is immutable. Rather than dealing with a convoluted workaround, + # lets wrap this in a function. + def _get_current_date(self): + """Gets the current date""" + return date.today() + def do_delete_domain(self, request, obj): if not isinstance(obj, Domain): # Could be problematic if the type is similar, diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 023e5319e..e3bb2adc9 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -920,6 +920,11 @@ class MockEppLib(TestCase): ex_date=datetime.date(2023, 5, 25), ) + mockButtonRenewedDomainExpDate = fakedEppObject( + "fakefuture.gov", + ex_date=datetime.date(2025, 5, 25), + ) + mockDnsNeededRenewedDomainExpDate = fakedEppObject( "fakeneeded.gov", ex_date=datetime.date(2023, 2, 15), @@ -1031,6 +1036,7 @@ class MockEppLib(TestCase): return None def mockRenewDomainCommand(self, _request, cleaned): + print(f"What is the request at this time? {_request}") if getattr(_request, "name", None) == "fake-error.gov": raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR) elif getattr(_request, "name", None) == "waterbutpurple.gov": @@ -1048,11 +1054,20 @@ class MockEppLib(TestCase): res_data=[self.mockMaximumRenewedDomainExpDate], code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY, ) - else: - return MagicMock( - res_data=[self.mockRenewedDomainExpDate], - code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY, - ) + elif getattr(_request, "name", None) == "fake.gov": + period = getattr(_request, "period", None) + extension_period = getattr(period, "length", None) + + if extension_period == 2: + return MagicMock( + res_data=[self.mockButtonRenewedDomainExpDate], + code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY, + ) + else: + return MagicMock( + res_data=[self.mockRenewedDomainExpDate], + code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY, + ) def mockInfoDomainCommands(self, _request, cleaned): request_name = getattr(_request, "name", None) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 6cc6f96ea..f5a60011c 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -49,6 +49,7 @@ logger = logging.getLogger(__name__) class TestDomainAdmin(MockEppLib, WebTest): csrf_checks = False + def setUp(self): self.site = AdminSite() self.admin = DomainAdmin(model=Domain, admin_site=self.site) @@ -61,6 +62,56 @@ class TestDomainAdmin(MockEppLib, WebTest): super().setUp() def test_extend_expiration_date_button(self): + """ + Tests if extend_expiration_date button extends correctly + """ + + # Create a ready domain with a preset expiration date + domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY) + + response = self.app.get(reverse("admin:registrar_domain_change", args=[domain.pk])) + + # Make sure that the page is loading as expected + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Extend expiration date") + + # Grab the form to submit + form = response.forms["domain_form"] + + with patch("django.contrib.messages.add_message") as mock_add_message: + # Submit the form + response = form.submit("_extend_expiration_date") + + # Follow the response + response = response.follow() + + # refresh_from_db() does not work for objects with protected=True. + # https://github.com/viewflow/django-fsm/issues/89 + new_domain = Domain.objects.get(id=domain.id) + + # Check that the current expiration date is what we expect + self.assertEqual(new_domain.expiration_date, date(2025, 5, 25)) + + # Assert that everything on the page looks correct + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Extend expiration date") + + # Ensure the message we recieve is in line with what we expect + expected_message = "Successfully extended the expiration date." + expected_call = call( + # The WGSI request doesn't need to be tested + ANY, + messages.INFO, + expected_message, + extra_tags="", + fail_silently=False, + ) + mock_add_message.assert_has_calls([expected_call], 1) + + @patch("registrar.admin.DomainAdmin._get_current_date", return_value=date(2024, 1, 1)) + def test_extend_expiration_date_button_epp(self, mock_date_today): """ Tests if extend_expiration_date button sends the right epp command """ @@ -74,7 +125,7 @@ class TestDomainAdmin(MockEppLib, WebTest): self.assertEqual(response.status_code, 200) self.assertContains(response, domain.name) self.assertContains(response, "Extend expiration date") - + # Grab the form to submit form = response.forms["domain_form"] @@ -85,14 +136,18 @@ class TestDomainAdmin(MockEppLib, WebTest): # Follow the response response = response.follow() - - # We need to use date.today() here, as it is not trivial - # to mock "date.today()". To do so requires libraries like freezegun, - # or convoluted workarounds. - extension_length = (date.today().year + 1) - 2023 - # Assert that it is calling the function + # This value is based off of the current year - the expiration date. + # We "freeze" time to 2024, so 2024 - 2023 will always result in an + # "extension" of 2, as that will be one year of extension from that date. + extension_length = 2 + + # Assert that it is calling the function with the right extension length. + # We only need to test the value that EPP sends, as we can assume the other + # test cases cover the "renew" function. renew_mock.assert_has_calls([call(length=extension_length)], any_order=False) + + # We should not make duplicate calls self.assertEqual(renew_mock.call_count, 1) # Assert that everything on the page looks correct @@ -101,7 +156,62 @@ class TestDomainAdmin(MockEppLib, WebTest): self.assertContains(response, "Extend expiration date") # Ensure the message we recieve is in line with what we expect - expected_message = f"Successfully extended the expiration date." + expected_message = "Successfully extended the expiration date." + expected_call = call( + # The WGSI request doesn't need to be tested + ANY, + messages.INFO, + expected_message, + extra_tags="", + fail_silently=False, + ) + mock_add_message.assert_has_calls([expected_call], 1) + + @patch("registrar.admin.DomainAdmin._get_current_date", return_value=date(2023, 1, 1)) + def test_extend_expiration_date_button_date_matches_epp(self, mock_date_today): + """ + Tests if extend_expiration_date button sends the right epp command + when the current year matches the expiration date + """ + + # Create a ready domain with a preset expiration date + domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY) + + response = self.app.get(reverse("admin:registrar_domain_change", args=[domain.pk])) + + # Make sure that the page is loading as expected + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Extend expiration date") + + # Grab the form to submit + form = response.forms["domain_form"] + + with patch("django.contrib.messages.add_message") as mock_add_message: + with patch("registrar.models.Domain.renew_domain") as renew_mock: + # Submit the form + response = form.submit("_extend_expiration_date") + + # Follow the response + response = response.follow() + + extension_length = 1 + + # Assert that it is calling the function with the right extension length. + # We only need to test the value that EPP sends, as we can assume the other + # test cases cover the "renew" function. + renew_mock.assert_has_calls([call(length=extension_length)], any_order=False) + + # We should not make duplicate calls + self.assertEqual(renew_mock.call_count, 1) + + # Assert that everything on the page looks correct + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Extend expiration date") + + # Ensure the message we recieve is in line with what we expect + expected_message = "Successfully extended the expiration date." expected_call = call( # The WGSI request doesn't need to be tested ANY,