Merge pull request #1521 from cisagov/rjm/1483-da-fsm-update

Issue 1483: Domain request FSM updates
This commit is contained in:
rachidatecs 2023-12-21 17:32:09 -05:00 committed by GitHub
commit 90c12031e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 337 additions and 396 deletions

View file

@ -585,7 +585,12 @@ class DomainApplication(TimeStampedModel):
@transition( @transition(
field="status", field="status",
source=[ApplicationStatus.STARTED, ApplicationStatus.ACTION_NEEDED, ApplicationStatus.WITHDRAWN], source=[
ApplicationStatus.STARTED,
ApplicationStatus.IN_REVIEW,
ApplicationStatus.ACTION_NEEDED,
ApplicationStatus.WITHDRAWN,
],
target=ApplicationStatus.SUBMITTED, target=ApplicationStatus.SUBMITTED,
) )
def submit(self): def submit(self):
@ -613,7 +618,17 @@ class DomainApplication(TimeStampedModel):
"emails/submission_confirmation_subject.txt", "emails/submission_confirmation_subject.txt",
) )
@transition(field="status", source=ApplicationStatus.SUBMITTED, target=ApplicationStatus.IN_REVIEW) @transition(
field="status",
source=[
ApplicationStatus.SUBMITTED,
ApplicationStatus.ACTION_NEEDED,
ApplicationStatus.APPROVED,
ApplicationStatus.REJECTED,
ApplicationStatus.INELIGIBLE,
],
target=ApplicationStatus.IN_REVIEW,
)
def in_review(self): def in_review(self):
"""Investigate an application that has been submitted. """Investigate an application that has been submitted.
@ -627,7 +642,12 @@ class DomainApplication(TimeStampedModel):
@transition( @transition(
field="status", field="status",
source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.REJECTED], source=[
ApplicationStatus.IN_REVIEW,
ApplicationStatus.APPROVED,
ApplicationStatus.REJECTED,
ApplicationStatus.INELIGIBLE,
],
target=ApplicationStatus.ACTION_NEEDED, target=ApplicationStatus.ACTION_NEEDED,
) )
def action_needed(self): def action_needed(self):
@ -646,8 +666,8 @@ class DomainApplication(TimeStampedModel):
source=[ source=[
ApplicationStatus.SUBMITTED, ApplicationStatus.SUBMITTED,
ApplicationStatus.IN_REVIEW, ApplicationStatus.IN_REVIEW,
ApplicationStatus.ACTION_NEEDED,
ApplicationStatus.REJECTED, ApplicationStatus.REJECTED,
ApplicationStatus.INELIGIBLE,
], ],
target=ApplicationStatus.APPROVED, target=ApplicationStatus.APPROVED,
) )
@ -684,7 +704,7 @@ class DomainApplication(TimeStampedModel):
@transition( @transition(
field="status", field="status",
source=[ApplicationStatus.SUBMITTED, ApplicationStatus.IN_REVIEW], source=[ApplicationStatus.SUBMITTED, ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED],
target=ApplicationStatus.WITHDRAWN, target=ApplicationStatus.WITHDRAWN,
) )
def withdraw(self): def withdraw(self):
@ -697,7 +717,7 @@ class DomainApplication(TimeStampedModel):
@transition( @transition(
field="status", field="status",
source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.APPROVED], source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED, ApplicationStatus.APPROVED],
target=ApplicationStatus.REJECTED, target=ApplicationStatus.REJECTED,
conditions=[domain_is_not_active], conditions=[domain_is_not_active],
) )
@ -707,12 +727,16 @@ class DomainApplication(TimeStampedModel):
As side effects this will delete the domain and domain_information As side effects this will delete the domain and domain_information
(will cascade), and send an email notification.""" (will cascade), and send an email notification."""
if self.status == self.ApplicationStatus.APPROVED: if self.status == self.ApplicationStatus.APPROVED:
domain_state = self.approved_domain.state try:
# Only reject if it exists on EPP domain_state = self.approved_domain.state
if domain_state != Domain.State.UNKNOWN: # Only reject if it exists on EPP
self.approved_domain.deletedInEpp() if domain_state != Domain.State.UNKNOWN:
self.approved_domain.delete() self.approved_domain.deletedInEpp()
self.approved_domain = None self.approved_domain.delete()
self.approved_domain = None
except Exception as err:
logger.error(err)
logger.error("Can't query an approved domain while attempting a DA reject()")
self._send_status_update_email( self._send_status_update_email(
"action needed", "action needed",
@ -722,7 +746,12 @@ class DomainApplication(TimeStampedModel):
@transition( @transition(
field="status", field="status",
source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.APPROVED], source=[
ApplicationStatus.IN_REVIEW,
ApplicationStatus.ACTION_NEEDED,
ApplicationStatus.APPROVED,
ApplicationStatus.REJECTED,
],
target=ApplicationStatus.INELIGIBLE, target=ApplicationStatus.INELIGIBLE,
conditions=[domain_is_not_active], conditions=[domain_is_not_active],
) )
@ -736,12 +765,16 @@ class DomainApplication(TimeStampedModel):
and domain_information (will cascade) when they exist.""" and domain_information (will cascade) when they exist."""
if self.status == self.ApplicationStatus.APPROVED: if self.status == self.ApplicationStatus.APPROVED:
domain_state = self.approved_domain.state try:
# Only reject if it exists on EPP domain_state = self.approved_domain.state
if domain_state != Domain.State.UNKNOWN: # Only reject if it exists on EPP
self.approved_domain.deletedInEpp() if domain_state != Domain.State.UNKNOWN:
self.approved_domain.delete() self.approved_domain.deletedInEpp()
self.approved_domain = None self.approved_domain.delete()
self.approved_domain = None
except Exception as err:
logger.error(err)
logger.error("Can't query an approved domain while attempting a DA reject_with_prejudice()")
self.creator.restrict_user() self.creator.restrict_user()

View file

@ -462,7 +462,7 @@ def completed_application(
): ):
"""A completed domain application.""" """A completed domain application."""
if not user: if not user:
user = get_user_model().objects.create(username="username") user = get_user_model().objects.create(username="username" + str(uuid.uuid4())[:8])
ao, _ = Contact.objects.get_or_create( ao, _ = Contact.objects.get_or_create(
first_name="Testy", first_name="Testy",
last_name="Tester", last_name="Tester",

View file

@ -26,20 +26,52 @@ boto3_mocking.clients.register_handler("sesv2", MockSESClient)
# with AWS SES, so mock that out in all of these test cases # with AWS SES, so mock that out in all of these test cases
@boto3_mocking.patching @boto3_mocking.patching
class TestDomainApplication(TestCase): class TestDomainApplication(TestCase):
def setUp(self):
self.started_application = completed_application(
status=DomainApplication.ApplicationStatus.STARTED, name="started.gov"
)
self.submitted_application = completed_application(
status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov"
)
self.in_review_application = completed_application(
status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov"
)
self.action_needed_application = completed_application(
status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov"
)
self.approved_application = completed_application(
status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov"
)
self.withdrawn_application = completed_application(
status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov"
)
self.rejected_application = completed_application(
status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov"
)
self.ineligible_application = completed_application(
status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov"
)
def assertNotRaises(self, exception_type):
"""Helper method for testing allowed transitions."""
return self.assertRaises(Exception, None, exception_type)
def test_empty_create_fails(self): def test_empty_create_fails(self):
"""Can't create a completely empty domain application.""" """Can't create a completely empty domain application.
NOTE: something about theexception this test raises messes up with the
atomic block in a custom tearDown method for the parent test class."""
with self.assertRaisesRegex(IntegrityError, "creator"): with self.assertRaisesRegex(IntegrityError, "creator"):
DomainApplication.objects.create() DomainApplication.objects.create()
def test_minimal_create(self): def test_minimal_create(self):
"""Can create with just a creator.""" """Can create with just a creator."""
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
application = DomainApplication.objects.create(creator=user) application = DomainApplication.objects.create(creator=user)
self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED) self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED)
def test_full_create(self): def test_full_create(self):
"""Can create with all fields.""" """Can create with all fields."""
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
contact = Contact.objects.create() contact = Contact.objects.create()
com_website, _ = Website.objects.get_or_create(website="igorville.com") com_website, _ = Website.objects.get_or_create(website="igorville.com")
gov_website, _ = Website.objects.get_or_create(website="igorville.gov") gov_website, _ = Website.objects.get_or_create(website="igorville.gov")
@ -69,7 +101,7 @@ class TestDomainApplication(TestCase):
def test_domain_info(self): def test_domain_info(self):
"""Can create domain info with all fields.""" """Can create domain info with all fields."""
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
contact = Contact.objects.create() contact = Contact.objects.create()
domain, _ = Domain.objects.get_or_create(name="igorville.gov") domain, _ = Domain.objects.get_or_create(name="igorville.gov")
information = DomainInformation.objects.create( information = DomainInformation.objects.create(
@ -95,14 +127,14 @@ class TestDomainApplication(TestCase):
self.assertEqual(information.id, domain.domain_info.id) self.assertEqual(information.id, domain.domain_info.id)
def test_status_fsm_submit_fail(self): def test_status_fsm_submit_fail(self):
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
application = DomainApplication.objects.create(creator=user) application = DomainApplication.objects.create(creator=user)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
# can't submit an application with a null domain name # can't submit an application with a null domain name
application.submit() application.submit()
def test_status_fsm_submit_succeed(self): def test_status_fsm_submit_succeed(self):
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
site = DraftDomain.objects.create(name="igorville.gov") site = DraftDomain.objects.create(name="igorville.gov")
application = DomainApplication.objects.create(creator=user, requested_domain=site) application = DomainApplication.objects.create(creator=user, requested_domain=site)
# no submitter email so this emits a log warning # no submitter email so this emits a log warning
@ -112,7 +144,7 @@ class TestDomainApplication(TestCase):
def test_submit_sends_email(self): def test_submit_sends_email(self):
"""Create an application and submit it and see if email was sent.""" """Create an application and submit it and see if email was sent."""
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create(username="testy")
contact = Contact.objects.create(email="test@test.gov") contact = Contact.objects.create(email="test@test.gov")
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
@ -135,320 +167,251 @@ class TestDomainApplication(TestCase):
0, 0,
) )
def test_transition_not_allowed_submitted_submitted(self): def test_submit_transition_allowed(self):
"""Create an application with status submitted and call submit """
against transition rules""" Test that calling submit from allowable statuses does raises TransitionNotAllowed.
"""
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED) test_cases = [
(self.started_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.in_review_application, TransitionNotAllowed),
application.submit() (self.action_needed_application, TransitionNotAllowed),
(self.withdrawn_application, TransitionNotAllowed),
def test_transition_not_allowed_in_review_submitted(self): ]
"""Create an application with status in review and call submit
against transition rules""" for application, exception_type in test_cases:
with self.subTest(application=application, exception_type=exception_type):
application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) try:
application.submit()
with self.assertRaises(TransitionNotAllowed): except TransitionNotAllowed:
application.submit() self.fail("TransitionNotAllowed was raised, but it was not expected.")
def test_transition_not_allowed_approved_submitted(self): def test_submit_transition_not_allowed(self):
"""Create an application with status approved and call submit """
against transition rules""" Test that calling submit against transition rules raises TransitionNotAllowed.
"""
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) test_cases = [
(self.submitted_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.approved_application, TransitionNotAllowed),
application.submit() (self.rejected_application, TransitionNotAllowed),
(self.ineligible_application, TransitionNotAllowed),
def test_transition_not_allowed_rejected_submitted(self): ]
"""Create an application with status rejected and call submit
against transition rules""" for application, exception_type in test_cases:
with self.subTest(application=application, exception_type=exception_type):
application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED) with self.assertRaises(exception_type):
application.submit()
with self.assertRaises(TransitionNotAllowed):
application.submit() def test_in_review_transition_allowed(self):
"""
def test_transition_not_allowed_ineligible_submitted(self): Test that calling in_review from allowable statuses does raises TransitionNotAllowed.
"""Create an application with status ineligible and call submit """
against transition rules""" test_cases = [
(self.submitted_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE) (self.action_needed_application, TransitionNotAllowed),
(self.approved_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.rejected_application, TransitionNotAllowed),
application.submit() (self.ineligible_application, TransitionNotAllowed),
]
def test_transition_not_allowed_started_in_review(self):
"""Create an application with status started and call in_review for application, exception_type in test_cases:
against transition rules""" with self.subTest(application=application, exception_type=exception_type):
try:
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED) application.in_review()
except TransitionNotAllowed:
with self.assertRaises(TransitionNotAllowed): self.fail("TransitionNotAllowed was raised, but it was not expected.")
application.in_review()
def test_in_review_transition_not_allowed(self):
def test_transition_not_allowed_in_review_in_review(self): """
"""Create an application with status in review and call in_review Test that calling in_review against transition rules raises TransitionNotAllowed.
against transition rules""" """
test_cases = [
application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) (self.started_application, TransitionNotAllowed),
(self.in_review_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.withdrawn_application, TransitionNotAllowed),
application.in_review() ]
def test_transition_not_allowed_approved_in_review(self): for application, exception_type in test_cases:
"""Create an application with status approved and call in_review with self.subTest(application=application, exception_type=exception_type):
against transition rules""" with self.assertRaises(exception_type):
application.in_review()
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED)
def test_action_needed_transition_allowed(self):
with self.assertRaises(TransitionNotAllowed): """
application.in_review() Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
"""
def test_transition_not_allowed_action_needed_in_review(self): test_cases = [
"""Create an application with status action needed and call in_review (self.in_review_application, TransitionNotAllowed),
against transition rules""" (self.approved_application, TransitionNotAllowed),
(self.rejected_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED) (self.ineligible_application, TransitionNotAllowed),
]
with self.assertRaises(TransitionNotAllowed):
application.in_review() for application, exception_type in test_cases:
with self.subTest(application=application, exception_type=exception_type):
def test_transition_not_allowed_rejected_in_review(self): try:
"""Create an application with status rejected and call in_review application.action_needed()
against transition rules""" except TransitionNotAllowed:
self.fail("TransitionNotAllowed was raised, but it was not expected.")
application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED)
def test_action_needed_transition_not_allowed(self):
with self.assertRaises(TransitionNotAllowed): """
application.in_review() Test that calling action_needed against transition rules raises TransitionNotAllowed.
"""
def test_transition_not_allowed_withdrawn_in_review(self): test_cases = [
"""Create an application with status withdrawn and call in_review (self.started_application, TransitionNotAllowed),
against transition rules""" (self.submitted_application, TransitionNotAllowed),
(self.action_needed_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN) (self.withdrawn_application, TransitionNotAllowed),
]
with self.assertRaises(TransitionNotAllowed):
application.in_review() for application, exception_type in test_cases:
with self.subTest(application=application, exception_type=exception_type):
def test_transition_not_allowed_ineligible_in_review(self): with self.assertRaises(exception_type):
"""Create an application with status ineligible and call in_review application.action_needed()
against transition rules"""
def test_approved_transition_allowed(self):
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE) """
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
with self.assertRaises(TransitionNotAllowed): """
application.in_review() test_cases = [
(self.submitted_application, TransitionNotAllowed),
def test_transition_not_allowed_started_action_needed(self): (self.in_review_application, TransitionNotAllowed),
"""Create an application with status started and call action_needed (self.action_needed_application, TransitionNotAllowed),
against transition rules""" (self.rejected_application, TransitionNotAllowed),
]
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED)
for application, exception_type in test_cases:
with self.assertRaises(TransitionNotAllowed): with self.subTest(application=application, exception_type=exception_type):
application.action_needed() try:
application.approve()
def test_transition_not_allowed_submitted_action_needed(self): except TransitionNotAllowed:
"""Create an application with status submitted and call action_needed self.fail("TransitionNotAllowed was raised, but it was not expected.")
against transition rules"""
def test_approved_transition_not_allowed(self):
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED) """
Test that calling action_needed against transition rules raises TransitionNotAllowed.
with self.assertRaises(TransitionNotAllowed): """
application.action_needed() test_cases = [
(self.started_application, TransitionNotAllowed),
def test_transition_not_allowed_action_needed_action_needed(self): (self.approved_application, TransitionNotAllowed),
"""Create an application with status action needed and call action_needed (self.withdrawn_application, TransitionNotAllowed),
against transition rules""" (self.ineligible_application, TransitionNotAllowed),
]
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED)
for application, exception_type in test_cases:
with self.assertRaises(TransitionNotAllowed): with self.subTest(application=application, exception_type=exception_type):
application.action_needed() with self.assertRaises(exception_type):
application.approve()
def test_transition_not_allowed_approved_action_needed(self):
"""Create an application with status approved and call action_needed def test_withdraw_transition_allowed(self):
against transition rules""" """
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) """
test_cases = [
with self.assertRaises(TransitionNotAllowed): (self.submitted_application, TransitionNotAllowed),
application.action_needed() (self.in_review_application, TransitionNotAllowed),
(self.action_needed_application, TransitionNotAllowed),
def test_transition_not_allowed_withdrawn_action_needed(self): ]
"""Create an application with status withdrawn and call action_needed
against transition rules""" for application, exception_type in test_cases:
with self.subTest(application=application, exception_type=exception_type):
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN) try:
application.withdraw()
with self.assertRaises(TransitionNotAllowed): except TransitionNotAllowed:
application.action_needed() self.fail("TransitionNotAllowed was raised, but it was not expected.")
def test_transition_not_allowed_ineligible_action_needed(self): def test_withdraw_transition_not_allowed(self):
"""Create an application with status ineligible and call action_needed """
against transition rules""" Test that calling action_needed against transition rules raises TransitionNotAllowed.
"""
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE) test_cases = [
(self.started_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.approved_application, TransitionNotAllowed),
application.action_needed() (self.withdrawn_application, TransitionNotAllowed),
(self.rejected_application, TransitionNotAllowed),
def test_transition_not_allowed_started_approved(self): (self.ineligible_application, TransitionNotAllowed),
"""Create an application with status started and call approve ]
against transition rules"""
for application, exception_type in test_cases:
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED) with self.subTest(application=application, exception_type=exception_type):
with self.assertRaises(exception_type):
with self.assertRaises(TransitionNotAllowed): application.withdraw()
application.approve()
def test_reject_transition_allowed(self):
def test_transition_not_allowed_approved_approved(self): """
"""Create an application with status approved and call approve Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
against transition rules""" """
test_cases = [
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) (self.in_review_application, TransitionNotAllowed),
(self.action_needed_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.approved_application, TransitionNotAllowed),
application.approve() ]
def test_transition_not_allowed_action_needed_approved(self): for application, exception_type in test_cases:
"""Create an application with status action needed and call approve with self.subTest(application=application, exception_type=exception_type):
against transition rules""" try:
application.reject()
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED) except TransitionNotAllowed:
self.fail("TransitionNotAllowed was raised, but it was not expected.")
with self.assertRaises(TransitionNotAllowed):
application.approve() def test_reject_transition_not_allowed(self):
"""
def test_transition_not_allowed_withdrawn_approved(self): Test that calling action_needed against transition rules raises TransitionNotAllowed.
"""Create an application with status withdrawn and call approve """
against transition rules""" test_cases = [
(self.started_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN) (self.submitted_application, TransitionNotAllowed),
(self.withdrawn_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): (self.rejected_application, TransitionNotAllowed),
application.approve() (self.ineligible_application, TransitionNotAllowed),
]
def test_transition_not_allowed_started_withdrawn(self):
"""Create an application with status started and call withdraw for application, exception_type in test_cases:
against transition rules""" with self.subTest(application=application, exception_type=exception_type):
with self.assertRaises(exception_type):
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED) application.reject()
with self.assertRaises(TransitionNotAllowed): def test_reject_with_prejudice_transition_allowed(self):
application.withdraw() """
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
def test_transition_not_allowed_approved_withdrawn(self): """
"""Create an application with status approved and call withdraw test_cases = [
against transition rules""" (self.in_review_application, TransitionNotAllowed),
(self.action_needed_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) (self.approved_application, TransitionNotAllowed),
(self.rejected_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): ]
application.withdraw()
for application, exception_type in test_cases:
def test_transition_not_allowed_action_needed_withdrawn(self): with self.subTest(application=application, exception_type=exception_type):
"""Create an application with status action needed and call withdraw try:
against transition rules""" application.reject_with_prejudice()
except TransitionNotAllowed:
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED) self.fail("TransitionNotAllowed was raised, but it was not expected.")
with self.assertRaises(TransitionNotAllowed): def test_reject_with_prejudice_transition_not_allowed(self):
application.withdraw() """
Test that calling action_needed against transition rules raises TransitionNotAllowed.
def test_transition_not_allowed_rejected_withdrawn(self): """
"""Create an application with status rejected and call withdraw test_cases = [
against transition rules""" (self.started_application, TransitionNotAllowed),
(self.submitted_application, TransitionNotAllowed),
application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED) (self.withdrawn_application, TransitionNotAllowed),
(self.ineligible_application, TransitionNotAllowed),
with self.assertRaises(TransitionNotAllowed): ]
application.withdraw()
for application, exception_type in test_cases:
def test_transition_not_allowed_withdrawn_withdrawn(self): with self.subTest(application=application, exception_type=exception_type):
"""Create an application with status withdrawn and call withdraw with self.assertRaises(exception_type):
against transition rules""" application.reject_with_prejudice()
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN)
with self.assertRaises(TransitionNotAllowed):
application.withdraw()
def test_transition_not_allowed_ineligible_withdrawn(self):
"""Create an application with status ineligible and call withdraw
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE)
with self.assertRaises(TransitionNotAllowed):
application.withdraw()
def test_transition_not_allowed_started_rejected(self):
"""Create an application with status started and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_submitted_rejected(self):
"""Create an application with status submitted and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_action_needed_rejected(self):
"""Create an application with status action needed and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_withdrawn_rejected(self):
"""Create an application with status withdrawn and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_rejected_rejected(self):
"""Create an application with status rejected and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_ineligible_rejected(self):
"""Create an application with status ineligible and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE)
with self.assertRaises(TransitionNotAllowed):
application.reject()
def test_transition_not_allowed_approved_rejected_when_domain_is_active(self): def test_transition_not_allowed_approved_rejected_when_domain_is_active(self):
"""Create an application with status approved, create a matching domain that """Create an application with status approved, create a matching domain that
is active, and call reject against transition rules""" is active, and call reject against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) domain = Domain.objects.create(name=self.approved_application.requested_domain.name)
domain = Domain.objects.create(name=application.requested_domain.name) self.approved_application.approved_domain = domain
application.approved_domain = domain self.approved_application.save()
application.save()
# Define a custom implementation for is_active # Define a custom implementation for is_active
def custom_is_active(self): def custom_is_active(self):
@ -458,70 +421,15 @@ class TestDomainApplication(TestCase):
with patch.object(Domain, "is_active", custom_is_active): with patch.object(Domain, "is_active", custom_is_active):
# Now, when you call is_active on Domain, it will return True # Now, when you call is_active on Domain, it will return True
with self.assertRaises(TransitionNotAllowed): with self.assertRaises(TransitionNotAllowed):
application.reject() self.approved_application.reject()
def test_transition_not_allowed_started_ineligible(self):
"""Create an application with status started and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.STARTED)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_submitted_ineligible(self):
"""Create an application with status submitted and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_action_needed_ineligible(self):
"""Create an application with status action needed and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_withdrawn_ineligible(self):
"""Create an application with status withdrawn and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_rejected_ineligible(self):
"""Create an application with status rejected and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_ineligible_ineligible(self):
"""Create an application with status ineligible and call reject
against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.INELIGIBLE)
with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice()
def test_transition_not_allowed_approved_ineligible_when_domain_is_active(self): def test_transition_not_allowed_approved_ineligible_when_domain_is_active(self):
"""Create an application with status approved, create a matching domain that """Create an application with status approved, create a matching domain that
is active, and call reject_with_prejudice against transition rules""" is active, and call reject_with_prejudice against transition rules"""
application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) domain = Domain.objects.create(name=self.approved_application.requested_domain.name)
domain = Domain.objects.create(name=application.requested_domain.name) self.approved_application.approved_domain = domain
application.approved_domain = domain self.approved_application.save()
application.save()
# Define a custom implementation for is_active # Define a custom implementation for is_active
def custom_is_active(self): def custom_is_active(self):
@ -531,7 +439,7 @@ class TestDomainApplication(TestCase):
with patch.object(Domain, "is_active", custom_is_active): with patch.object(Domain, "is_active", custom_is_active):
# Now, when you call is_active on Domain, it will return True # Now, when you call is_active on Domain, it will return True
with self.assertRaises(TransitionNotAllowed): with self.assertRaises(TransitionNotAllowed):
application.reject_with_prejudice() self.approved_application.reject_with_prejudice()
class TestPermissions(TestCase): class TestPermissions(TestCase):