Unit test the unallowed transitions, error message on admin, and side effects of successful transitions

This commit is contained in:
Rachid Mrad 2023-09-06 15:19:32 -04:00
parent 324bea9868
commit 5fd84b534d
No known key found for this signature in database
GPG key ID: EF38E4CEC4A8F3CF
2 changed files with 195 additions and 1 deletions

View file

@ -1,5 +1,8 @@
from django.test import TestCase, RequestFactory, Client from django.test import TestCase, RequestFactory, Client
from django.contrib.admin.sites import AdminSite from django.contrib.admin.sites import AdminSite
from unittest.mock import patch
from contextlib import ExitStack
from django.contrib import messages
from registrar.admin import ( from registrar.admin import (
DomainApplicationAdmin, DomainApplicationAdmin,
@ -10,6 +13,7 @@ from registrar.admin import (
from registrar.models import ( from registrar.models import (
DomainApplication, DomainApplication,
DomainInformation, DomainInformation,
Domain,
User, User,
DomainInvitation, DomainInvitation,
) )
@ -432,8 +436,159 @@ class TestDomainApplicationAdmin(TestCase):
request, request,
"Cannot edit an application with a restricted creator.", "Cannot edit an application with a restricted creator.",
) )
def test_error_when_saving_approved_to_rejected_and_domain_is_active(self):
# Create an instance of the model
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
application.approved_domain = domain
application.save()
# Create a request object with a superuser
request = self.factory.post(
"/admin/registrar/domainapplication/{}/change/".format(application.pk)
)
request.user = self.superuser
# Define a custom implementation for is_active
def custom_is_active(self):
return True # Override to return True
# Use ExitStack to combine patch contexts
with ExitStack() as stack:
# Patch Domain.is_active and django.contrib.messages.error simultaneously
stack.enter_context(patch.object(Domain, 'is_active', custom_is_active))
stack.enter_context(patch.object(messages, 'error'))
# Simulate saving the model
application.status = DomainApplication.REJECTED
self.admin.save_model(request, application, None, True)
# Assert that the error message was called with the correct argument
messages.error.assert_called_once_with(
request,
"This action is not permitted, the domain "
+ "is already active.",
)
def test_side_effects_when_saving_approved_to_rejected(self):
# Create an instance of the model
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
domain_information = DomainInformation.objects.create(creator=self.superuser, domain=domain)
application.approved_domain = domain
application.save()
# Create a request object with a superuser
request = self.factory.post(
"/admin/registrar/domainapplication/{}/change/".format(application.pk)
)
request.user = self.superuser
# Define a custom implementation for is_active
def custom_is_active(self):
return False # Override to return False
# Use ExitStack to combine patch contexts
with ExitStack() as stack:
# Patch Domain.is_active and django.contrib.messages.error simultaneously
stack.enter_context(patch.object(Domain, 'is_active', custom_is_active))
stack.enter_context(patch.object(messages, 'error'))
# Simulate saving the model
application.status = DomainApplication.REJECTED
self.admin.save_model(request, application, None, True)
# Assert that the error message was never called
messages.error.assert_not_called()
self.assertEqual(application.approved_domain, None)
# Assert that Domain got Deleted
with self.assertRaises(Domain.DoesNotExist):
domain.refresh_from_db()
# Assert that DomainInformation got Deleted
with self.assertRaises(DomainInformation.DoesNotExist):
domain_information.refresh_from_db()
def test_error_when_saving_approved_to_ineligible_and_domain_is_active(self):
# Create an instance of the model
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
application.approved_domain = domain
application.save()
# Create a request object with a superuser
request = self.factory.post(
"/admin/registrar/domainapplication/{}/change/".format(application.pk)
)
request.user = self.superuser
# Define a custom implementation for is_active
def custom_is_active(self):
return True # Override to return True
# Use ExitStack to combine patch contexts
with ExitStack() as stack:
# Patch Domain.is_active and django.contrib.messages.error simultaneously
stack.enter_context(patch.object(Domain, 'is_active', custom_is_active))
stack.enter_context(patch.object(messages, 'error'))
# Simulate saving the model
application.status = DomainApplication.INELIGIBLE
self.admin.save_model(request, application, None, True)
# Assert that the error message was called with the correct argument
messages.error.assert_called_once_with(
request,
"This action is not permitted, the domain "
+ "is already active.",
)
def test_side_effects_when_saving_approved_to_ineligible(self):
# Create an instance of the model
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
domain_information = DomainInformation.objects.create(creator=self.superuser, domain=domain)
application.approved_domain = domain
application.save()
# Create a request object with a superuser
request = self.factory.post(
"/admin/registrar/domainapplication/{}/change/".format(application.pk)
)
request.user = self.superuser
# Define a custom implementation for is_active
def custom_is_active(self):
return False # Override to return False
# Use ExitStack to combine patch contexts
with ExitStack() as stack:
# Patch Domain.is_active and django.contrib.messages.error simultaneously
stack.enter_context(patch.object(Domain, 'is_active', custom_is_active))
stack.enter_context(patch.object(messages, 'error'))
# Simulate saving the model
application.status = DomainApplication.INELIGIBLE
self.admin.save_model(request, application, None, True)
# Assert that the error message was never called
messages.error.assert_not_called()
self.assertEqual(application.approved_domain, None)
# Assert that Domain got Deleted
with self.assertRaises(Domain.DoesNotExist):
domain.refresh_from_db()
# Assert that DomainInformation got Deleted
with self.assertRaises(DomainInformation.DoesNotExist):
domain_information.refresh_from_db()
def tearDown(self): def tearDown(self):
Domain.objects.all().delete()
DomainInformation.objects.all().delete() DomainInformation.objects.all().delete()
DomainApplication.objects.all().delete() DomainApplication.objects.all().delete()
User.objects.all().delete() User.objects.all().delete()

View file

@ -1,5 +1,6 @@
from django.test import TestCase from django.test import TestCase
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
from unittest.mock import patch
from registrar.models import ( from registrar.models import (
Contact, Contact,
@ -439,7 +440,26 @@ class TestDomainApplication(TestCase):
application = completed_application(status=DomainApplication.INELIGIBLE) application = completed_application(status=DomainApplication.INELIGIBLE)
with self.assertRaises(TransitionNotAllowed): with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice() application.reject()
def test_transition_not_allowed_approved_rejected_when_domain_is_active(self):
"""Create an application with status approved, create a matching domain that
is active, and call reject against transition rules"""
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
application.approved_domain = domain
application.save()
# Define a custom implementation for is_active
def custom_is_active(self):
return True # Override to return True
# Use patch to temporarily replace is_active with the custom implementation
with patch.object(Domain, 'is_active', custom_is_active):
# Now, when you call is_active on Domain, it will return True
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_started_ineligible(self): def test_transition_not_allowed_started_ineligible(self):
"""Create an application with status started and call reject """Create an application with status started and call reject
@ -494,6 +514,25 @@ class TestDomainApplication(TestCase):
with self.assertRaises(TransitionNotAllowed): with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice() application.reject_with_prejudice()
def test_transition_not_allowed_approved_ineligible_when_domain_is_active(self):
"""Create an application with status approved, create a matching domain that
is active, and call reject_with_prejudice against transition rules"""
application = completed_application(status=DomainApplication.APPROVED)
domain = Domain.objects.create(name=application.requested_domain.name)
application.approved_domain = domain
application.save()
# Define a custom implementation for is_active
def custom_is_active(self):
return True # Override to return True
# Use patch to temporarily replace is_active with the custom implementation
with patch.object(Domain, 'is_active', custom_is_active):
# Now, when you call is_active on Domain, it will return True
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
class TestPermissions(TestCase): class TestPermissions(TestCase):