mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 17:17:02 +02:00
2377 lines
106 KiB
Python
2377 lines
106 KiB
Python
from django.forms import ValidationError
|
|
from django.test import TestCase
|
|
from django.db.utils import IntegrityError
|
|
from django.db import transaction
|
|
from unittest.mock import patch
|
|
|
|
from django.test import RequestFactory
|
|
|
|
from registrar.models import (
|
|
Contact,
|
|
DomainRequest,
|
|
DomainInformation,
|
|
User,
|
|
Website,
|
|
Domain,
|
|
DraftDomain,
|
|
DomainInvitation,
|
|
UserDomainRole,
|
|
FederalAgency,
|
|
)
|
|
|
|
import boto3_mocking
|
|
from registrar.models.portfolio import Portfolio
|
|
from registrar.models.portfolio_invitation import PortfolioInvitation
|
|
from registrar.models.transition_domain import TransitionDomain
|
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
|
from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore
|
|
from registrar.utility.constants import BranchChoices
|
|
|
|
from .common import (
|
|
MockSESClient,
|
|
less_console_noise,
|
|
completed_domain_request,
|
|
set_domain_request_investigators,
|
|
create_test_user,
|
|
)
|
|
from django_fsm import TransitionNotAllowed
|
|
from waffle.testutils import override_flag
|
|
|
|
from api.tests.common import less_console_noise_decorator
|
|
|
|
|
|
@boto3_mocking.patching
|
|
class TestDomainRequest(TestCase):
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
|
|
self.dummy_user, _ = Contact.objects.get_or_create(
|
|
email="mayor@igorville.com", first_name="Hello", last_name="World"
|
|
)
|
|
self.dummy_user_2, _ = User.objects.get_or_create(
|
|
username="intern@igorville.com", email="intern@igorville.com", first_name="Lava", last_name="World"
|
|
)
|
|
self.started_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
)
|
|
self.submitted_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
|
name="submitted.gov",
|
|
)
|
|
self.in_review_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW,
|
|
name="in-review.gov",
|
|
)
|
|
self.action_needed_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
|
name="action-needed.gov",
|
|
)
|
|
self.approved_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.APPROVED,
|
|
name="approved.gov",
|
|
)
|
|
self.withdrawn_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
|
name="withdrawn.gov",
|
|
)
|
|
self.rejected_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
|
name="rejected.gov",
|
|
)
|
|
self.ineligible_domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.INELIGIBLE,
|
|
name="ineligible.gov",
|
|
)
|
|
|
|
# Store all domain request statuses in a variable for ease of use
|
|
self.all_domain_requests = [
|
|
self.started_domain_request,
|
|
self.submitted_domain_request,
|
|
self.in_review_domain_request,
|
|
self.action_needed_domain_request,
|
|
self.approved_domain_request,
|
|
self.withdrawn_domain_request,
|
|
self.rejected_domain_request,
|
|
self.ineligible_domain_request,
|
|
]
|
|
|
|
self.mock_client = MockSESClient()
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
DomainInformation.objects.all().delete()
|
|
DomainRequest.objects.all().delete()
|
|
DraftDomain.objects.all().delete()
|
|
Domain.objects.all().delete()
|
|
User.objects.all().delete()
|
|
self.mock_client.EMAILS_SENT.clear()
|
|
|
|
def assertNotRaises(self, exception_type):
|
|
"""Helper method for testing allowed transitions."""
|
|
with less_console_noise():
|
|
return self.assertRaises(Exception, None, exception_type)
|
|
|
|
@less_console_noise_decorator
|
|
def test_federal_agency_set_to_non_federal_on_approve(self):
|
|
"""Ensures that when the federal_agency field is 'none' when .approve() is called,
|
|
the field is set to the 'Non-Federal Agency' record"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW,
|
|
name="city2.gov",
|
|
federal_agency=None,
|
|
)
|
|
|
|
# Ensure that the federal agency is None
|
|
self.assertEqual(domain_request.federal_agency, None)
|
|
|
|
# Approve the request
|
|
domain_request.approve()
|
|
self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.APPROVED)
|
|
|
|
# After approval, it should be "Non-Federal agency"
|
|
expected_federal_agency = FederalAgency.objects.filter(agency="Non-Federal Agency").first()
|
|
self.assertEqual(domain_request.federal_agency, expected_federal_agency)
|
|
|
|
def test_empty_create_fails(self):
|
|
"""Can't create a completely empty domain request."""
|
|
with less_console_noise():
|
|
with transaction.atomic():
|
|
with self.assertRaisesRegex(IntegrityError, "creator"):
|
|
DomainRequest.objects.create()
|
|
|
|
@less_console_noise_decorator
|
|
def test_minimal_create(self):
|
|
"""Can create with just a creator."""
|
|
user, _ = User.objects.get_or_create(username="testy")
|
|
domain_request = DomainRequest.objects.create(creator=user)
|
|
self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.STARTED)
|
|
|
|
@less_console_noise_decorator
|
|
def test_full_create(self):
|
|
"""Can create with all fields."""
|
|
user, _ = User.objects.get_or_create(username="testy")
|
|
contact = Contact.objects.create()
|
|
com_website, _ = Website.objects.get_or_create(website="igorville.com")
|
|
gov_website, _ = Website.objects.get_or_create(website="igorville.gov")
|
|
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
|
domain_request = DomainRequest.objects.create(
|
|
creator=user,
|
|
investigator=user,
|
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
|
federal_type=BranchChoices.EXECUTIVE,
|
|
is_election_board=False,
|
|
organization_name="Test",
|
|
address_line1="100 Main St.",
|
|
address_line2="APT 1A",
|
|
state_territory="CA",
|
|
zipcode="12345-6789",
|
|
senior_official=contact,
|
|
requested_domain=domain,
|
|
submitter=contact,
|
|
purpose="Igorville rules!",
|
|
anything_else="All of Igorville loves the dotgov program.",
|
|
is_policy_acknowledged=True,
|
|
)
|
|
domain_request.current_websites.add(com_website)
|
|
domain_request.alternative_domains.add(gov_website)
|
|
domain_request.other_contacts.add(contact)
|
|
domain_request.save()
|
|
|
|
@less_console_noise_decorator
|
|
def test_domain_info(self):
|
|
"""Can create domain info with all fields."""
|
|
user, _ = User.objects.get_or_create(username="testy")
|
|
contact = Contact.objects.create()
|
|
domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
|
information = DomainInformation.objects.create(
|
|
creator=user,
|
|
generic_org_type=DomainInformation.OrganizationChoices.FEDERAL,
|
|
federal_type=BranchChoices.EXECUTIVE,
|
|
is_election_board=False,
|
|
organization_name="Test",
|
|
address_line1="100 Main St.",
|
|
address_line2="APT 1A",
|
|
state_territory="CA",
|
|
zipcode="12345-6789",
|
|
senior_official=contact,
|
|
submitter=contact,
|
|
purpose="Igorville rules!",
|
|
anything_else="All of Igorville loves the dotgov program.",
|
|
is_policy_acknowledged=True,
|
|
domain=domain,
|
|
)
|
|
information.other_contacts.add(contact)
|
|
information.save()
|
|
self.assertEqual(information.domain.id, domain.id)
|
|
self.assertEqual(information.id, domain.domain_info.id)
|
|
|
|
@less_console_noise_decorator
|
|
def test_status_fsm_submit_fail(self):
|
|
user, _ = User.objects.get_or_create(username="testy")
|
|
domain_request = DomainRequest.objects.create(creator=user)
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
with less_console_noise():
|
|
with self.assertRaises(ValueError):
|
|
# can't submit a domain request with a null domain name
|
|
domain_request.submit()
|
|
|
|
@less_console_noise_decorator
|
|
def test_status_fsm_submit_succeed(self):
|
|
user, _ = User.objects.get_or_create(username="testy")
|
|
site = DraftDomain.objects.create(name="igorville.gov")
|
|
domain_request = DomainRequest.objects.create(creator=user, requested_domain=site)
|
|
|
|
# no submitter email so this emits a log warning
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
with less_console_noise():
|
|
domain_request.submit()
|
|
self.assertEqual(domain_request.status, domain_request.DomainRequestStatus.SUBMITTED)
|
|
|
|
@less_console_noise_decorator
|
|
def check_email_sent(
|
|
self, domain_request, msg, action, expected_count, expected_content=None, expected_email="mayor@igorville.com"
|
|
):
|
|
"""Check if an email was sent after performing an action."""
|
|
|
|
with self.subTest(msg=msg, action=action):
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# Perform the specified action
|
|
action_method = getattr(domain_request, action)
|
|
action_method()
|
|
|
|
# Check if an email was sent
|
|
sent_emails = [
|
|
email
|
|
for email in MockSESClient.EMAILS_SENT
|
|
if expected_email in email["kwargs"]["Destination"]["ToAddresses"]
|
|
]
|
|
self.assertEqual(len(sent_emails), expected_count)
|
|
|
|
if expected_content:
|
|
email_content = sent_emails[0]["kwargs"]["Content"]["Simple"]["Body"]["Text"]["Data"]
|
|
self.assertIn(expected_content, email_content)
|
|
|
|
@override_flag("profile_feature", active=False)
|
|
@less_console_noise_decorator
|
|
def test_submit_from_started_sends_email(self):
|
|
msg = "Create a domain request and submit it and see if email was sent."
|
|
domain_request = completed_domain_request(submitter=self.dummy_user, user=self.dummy_user_2)
|
|
self.check_email_sent(domain_request, msg, "submit", 1, expected_content="Hello")
|
|
|
|
@override_flag("profile_feature", active=True)
|
|
@less_console_noise_decorator
|
|
def test_submit_from_started_sends_email_to_creator(self):
|
|
"""Tests if, when the profile feature flag is on, we send an email to the creator"""
|
|
msg = "Create a domain request and submit it and see if email was sent when the feature flag is on."
|
|
domain_request = completed_domain_request(submitter=self.dummy_user, user=self.dummy_user_2)
|
|
self.check_email_sent(
|
|
domain_request, msg, "submit", 1, expected_content="Lava", expected_email="intern@igorville.com"
|
|
)
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_from_withdrawn_sends_email(self):
|
|
msg = "Create a withdrawn domain request and submit it and see if email was sent."
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN, submitter=self.dummy_user
|
|
)
|
|
self.check_email_sent(domain_request, msg, "submit", 1, expected_content="Hello")
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_from_action_needed_does_not_send_email(self):
|
|
msg = "Create a domain request with ACTION_NEEDED status and submit it, check if email was not sent."
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.ACTION_NEEDED)
|
|
self.check_email_sent(domain_request, msg, "submit", 0)
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_from_in_review_does_not_send_email(self):
|
|
msg = "Create a withdrawn domain request and submit it and see if email was sent."
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW)
|
|
self.check_email_sent(domain_request, msg, "submit", 0)
|
|
|
|
@less_console_noise_decorator
|
|
def test_approve_sends_email(self):
|
|
msg = "Create a domain request and approve it and see if email was sent."
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW, submitter=self.dummy_user
|
|
)
|
|
self.check_email_sent(domain_request, msg, "approve", 1, expected_content="Hello")
|
|
|
|
@less_console_noise_decorator
|
|
def test_withdraw_sends_email(self):
|
|
msg = "Create a domain request and withdraw it and see if email was sent."
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW, submitter=self.dummy_user
|
|
)
|
|
self.check_email_sent(domain_request, msg, "withdraw", 1, expected_content="Hello")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_sends_email(self):
|
|
msg = "Create a domain request and reject it and see if email was sent."
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.APPROVED, submitter=self.dummy_user
|
|
)
|
|
self.check_email_sent(domain_request, msg, "reject", 1, expected_content="Hello")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_with_prejudice_does_not_send_email(self):
|
|
msg = "Create a domain request and reject it with prejudice and see if email was sent."
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED)
|
|
self.check_email_sent(domain_request, msg, "reject_with_prejudice", 0)
|
|
|
|
@less_console_noise_decorator
|
|
def assert_fsm_transition_raises_error(self, test_cases, method_to_run):
|
|
"""Given a list of test cases, check if each transition throws the intended error"""
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise():
|
|
for domain_request, exception_type in test_cases:
|
|
with self.subTest(domain_request=domain_request, exception_type=exception_type):
|
|
with self.assertRaises(exception_type):
|
|
# Retrieve the method by name from the domain_request object and call it
|
|
method = getattr(domain_request, method_to_run)
|
|
# Call the method
|
|
method()
|
|
|
|
@less_console_noise_decorator
|
|
def assert_fsm_transition_does_not_raise_error(self, test_cases, method_to_run):
|
|
"""Given a list of test cases, ensure that none of them throw transition errors"""
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise():
|
|
for domain_request, exception_type in test_cases:
|
|
with self.subTest(domain_request=domain_request, exception_type=exception_type):
|
|
try:
|
|
# Retrieve the method by name from the DomainRequest object and call it
|
|
method = getattr(domain_request, method_to_run)
|
|
# Call the method
|
|
method()
|
|
except exception_type:
|
|
self.fail(f"{exception_type} was raised, but it was not expected.")
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_transition_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator.
|
|
For submit, this should be valid in all cases.
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "submit")
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_transition_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition with an investigator user that is not staff.
|
|
For submit, this should be valid in all cases.
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "submit")
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_transition_allowed(self):
|
|
"""
|
|
Test that calling submit from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "submit")
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_transition_allowed_twice(self):
|
|
"""
|
|
Test that rotating between submit and in_review doesn't throw an error
|
|
"""
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
try:
|
|
# Make a submission
|
|
self.in_review_domain_request.submit()
|
|
|
|
# Rerun the old method to get back to the original state
|
|
self.in_review_domain_request.in_review()
|
|
|
|
# Make another submission
|
|
self.in_review_domain_request.submit()
|
|
except TransitionNotAllowed:
|
|
self.fail("TransitionNotAllowed was raised, but it was not expected.")
|
|
|
|
self.assertEqual(self.in_review_domain_request.status, DomainRequest.DomainRequestStatus.SUBMITTED)
|
|
|
|
@less_console_noise_decorator
|
|
def test_submit_transition_not_allowed(self):
|
|
"""
|
|
Test that calling submit against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "submit")
|
|
|
|
@less_console_noise_decorator
|
|
def test_in_review_transition_allowed(self):
|
|
"""
|
|
Test that calling in_review from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "in_review")
|
|
|
|
@less_console_noise_decorator
|
|
def test_in_review_transition_not_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "in_review")
|
|
|
|
@less_console_noise_decorator
|
|
def test_in_review_transition_not_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition with an investigator that is not staff.
|
|
This should throw an exception.
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "in_review")
|
|
|
|
@less_console_noise_decorator
|
|
def test_in_review_transition_not_allowed(self):
|
|
"""
|
|
Test that calling in_review against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "in_review")
|
|
|
|
@less_console_noise_decorator
|
|
def test_action_needed_transition_allowed(self):
|
|
"""
|
|
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "action_needed")
|
|
|
|
@less_console_noise_decorator
|
|
def test_action_needed_transition_not_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "action_needed")
|
|
|
|
@less_console_noise_decorator
|
|
def test_action_needed_transition_not_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition with an investigator that is not staff
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "action_needed")
|
|
|
|
@less_console_noise_decorator
|
|
def test_action_needed_transition_not_allowed(self):
|
|
"""
|
|
Test that calling action_needed against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "action_needed")
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_transition_allowed(self):
|
|
"""
|
|
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "approve")
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_transition_not_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "approve")
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_transition_not_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition with an investigator that is not staff
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "approve")
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_skips_sending_email(self):
|
|
"""
|
|
Test that calling .approve with send_email=False doesn't actually send
|
|
an email
|
|
"""
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
self.submitted_domain_request.approve(send_email=False)
|
|
|
|
# Assert that no emails were sent
|
|
self.assertEqual(len(self.mock_client.EMAILS_SENT), 0)
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_transition_not_allowed(self):
|
|
"""
|
|
Test that calling action_needed against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
self.assert_fsm_transition_raises_error(test_cases, "approve")
|
|
|
|
@less_console_noise_decorator
|
|
def test_withdraw_transition_allowed(self):
|
|
"""
|
|
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw")
|
|
|
|
@less_console_noise_decorator
|
|
def test_withdraw_transition_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator.
|
|
For withdraw, this should be valid in all cases.
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw")
|
|
|
|
@less_console_noise_decorator
|
|
def test_withdraw_transition_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition when investigator is not staff.
|
|
For withdraw, this should be valid in all cases.
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw")
|
|
|
|
@less_console_noise_decorator
|
|
def test_withdraw_transition_not_allowed(self):
|
|
"""
|
|
Test that calling action_needed against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "withdraw")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_transition_allowed(self):
|
|
"""
|
|
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "reject")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_transition_not_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_transition_not_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition when investigator is not staff
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_transition_not_allowed(self):
|
|
"""
|
|
Test that calling action_needed against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_with_prejudice_transition_allowed(self):
|
|
"""
|
|
Test that calling action_needed from allowable statuses does raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_does_not_raise_error(test_cases, "reject_with_prejudice")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_with_prejudice_transition_not_allowed_with_no_investigator(self):
|
|
"""
|
|
Tests for attempting to transition without an investigator
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to none
|
|
set_domain_request_investigators(self.all_domain_requests, None)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_with_prejudice_not_allowed_with_investigator_not_staff(self):
|
|
"""
|
|
Tests for attempting to transition when investigator is not staff
|
|
"""
|
|
|
|
test_cases = [
|
|
(self.in_review_domain_request, TransitionNotAllowed),
|
|
(self.action_needed_domain_request, TransitionNotAllowed),
|
|
(self.approved_domain_request, TransitionNotAllowed),
|
|
(self.rejected_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
# Set all investigators to a user with no staff privs
|
|
user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False)
|
|
set_domain_request_investigators(self.all_domain_requests, user)
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice")
|
|
|
|
@less_console_noise_decorator
|
|
def test_reject_with_prejudice_transition_not_allowed(self):
|
|
"""
|
|
Test that calling action_needed against transition rules raises TransitionNotAllowed.
|
|
"""
|
|
test_cases = [
|
|
(self.started_domain_request, TransitionNotAllowed),
|
|
(self.submitted_domain_request, TransitionNotAllowed),
|
|
(self.withdrawn_domain_request, TransitionNotAllowed),
|
|
(self.ineligible_domain_request, TransitionNotAllowed),
|
|
]
|
|
|
|
self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice")
|
|
|
|
@less_console_noise_decorator
|
|
def test_transition_not_allowed_approved_in_review_when_domain_is_active(self):
|
|
"""Create a domain request with status approved, create a matching domain that
|
|
is active, and call in_review against transition rules"""
|
|
|
|
domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name)
|
|
self.approved_domain_request.approved_domain = domain
|
|
self.approved_domain_request.save()
|
|
|
|
# Define a custom implementation for is_active
|
|
def custom_is_active(self):
|
|
return True # Override to return True
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# 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):
|
|
self.approved_domain_request.in_review()
|
|
|
|
@less_console_noise_decorator
|
|
def test_transition_not_allowed_approved_action_needed_when_domain_is_active(self):
|
|
"""Create a domain request with status approved, create a matching domain that
|
|
is active, and call action_needed against transition rules"""
|
|
|
|
domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name)
|
|
self.approved_domain_request.approved_domain = domain
|
|
self.approved_domain_request.save()
|
|
|
|
# Define a custom implementation for is_active
|
|
def custom_is_active(self):
|
|
return True # Override to return True
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# 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):
|
|
self.approved_domain_request.action_needed()
|
|
|
|
@less_console_noise_decorator
|
|
def test_transition_not_allowed_approved_rejected_when_domain_is_active(self):
|
|
"""Create a domain request with status approved, create a matching domain that
|
|
is active, and call reject against transition rules"""
|
|
|
|
domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name)
|
|
self.approved_domain_request.approved_domain = domain
|
|
self.approved_domain_request.save()
|
|
|
|
# Define a custom implementation for is_active
|
|
def custom_is_active(self):
|
|
return True # Override to return True
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# 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):
|
|
self.approved_domain_request.reject()
|
|
|
|
@less_console_noise_decorator
|
|
def test_transition_not_allowed_approved_ineligible_when_domain_is_active(self):
|
|
"""Create a domain request with status approved, create a matching domain that
|
|
is active, and call reject_with_prejudice against transition rules"""
|
|
|
|
domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name)
|
|
self.approved_domain_request.approved_domain = domain
|
|
self.approved_domain_request.save()
|
|
|
|
# Define a custom implementation for is_active
|
|
def custom_is_active(self):
|
|
return True # Override to return True
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# 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):
|
|
self.approved_domain_request.reject_with_prejudice()
|
|
|
|
@less_console_noise_decorator
|
|
def test_approve_from_rejected_clears_rejection_reason(self):
|
|
"""When transitioning from rejected to approved on a domain request,
|
|
the rejection_reason is cleared."""
|
|
|
|
# Create a sample domain request
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED)
|
|
domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE
|
|
|
|
# Approve
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
domain_request.approve()
|
|
|
|
self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.APPROVED)
|
|
self.assertEqual(domain_request.rejection_reason, None)
|
|
|
|
@less_console_noise_decorator
|
|
def test_in_review_from_rejected_clears_rejection_reason(self):
|
|
"""When transitioning from rejected to in_review on a domain request,
|
|
the rejection_reason is cleared."""
|
|
|
|
# Create a sample domain request
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED)
|
|
domain_request.domain_is_not_active = True
|
|
domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE
|
|
|
|
# Approve
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
domain_request.in_review()
|
|
|
|
self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.IN_REVIEW)
|
|
self.assertEqual(domain_request.rejection_reason, None)
|
|
|
|
@less_console_noise_decorator
|
|
def test_action_needed_from_rejected_clears_rejection_reason(self):
|
|
"""When transitioning from rejected to action_needed on a domain request,
|
|
the rejection_reason is cleared."""
|
|
|
|
# Create a sample domain request
|
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED)
|
|
domain_request.domain_is_not_active = True
|
|
domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE
|
|
|
|
# Approve
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
domain_request.action_needed()
|
|
|
|
self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.ACTION_NEEDED)
|
|
self.assertEqual(domain_request.rejection_reason, None)
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_rationale_returns_true(self):
|
|
"""has_rationale() returns true when a domain request has no_other_contacts_rationale"""
|
|
self.started_domain_request.no_other_contacts_rationale = "You talkin' to me?"
|
|
self.started_domain_request.save()
|
|
self.assertEquals(self.started_domain_request.has_rationale(), True)
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_rationale_returns_false(self):
|
|
"""has_rationale() returns false when a domain request has no no_other_contacts_rationale"""
|
|
self.assertEquals(self.started_domain_request.has_rationale(), False)
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_other_contacts_returns_true(self):
|
|
"""has_other_contacts() returns true when a domain request has other_contacts"""
|
|
# completed_domain_request has other contacts by default
|
|
self.assertEquals(self.started_domain_request.has_other_contacts(), True)
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_other_contacts_returns_false(self):
|
|
"""has_other_contacts() returns false when a domain request has no other_contacts"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED, name="no-others.gov", has_other_contacts=False
|
|
)
|
|
self.assertEquals(domain_request.has_other_contacts(), False)
|
|
|
|
|
|
class TestPermissions(TestCase):
|
|
"""Test the User-Domain-Role connection."""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.mock_client = MockSESClient()
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
self.mock_client.EMAILS_SENT.clear()
|
|
|
|
@boto3_mocking.patching
|
|
@less_console_noise_decorator
|
|
def test_approval_creates_role(self):
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
|
user, _ = User.objects.get_or_create()
|
|
investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True)
|
|
domain_request = DomainRequest.objects.create(
|
|
creator=user, requested_domain=draft_domain, investigator=investigator
|
|
)
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# skip using the submit method
|
|
domain_request.status = DomainRequest.DomainRequestStatus.SUBMITTED
|
|
domain_request.approve()
|
|
|
|
# should be a role for this user
|
|
domain = Domain.objects.get(name="igorville.gov")
|
|
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
|
|
|
|
|
|
class TestDomainInformation(TestCase):
|
|
"""Test the DomainInformation model, when approved or otherwise"""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.mock_client = MockSESClient()
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
self.mock_client.EMAILS_SENT.clear()
|
|
Domain.objects.all().delete()
|
|
DomainInformation.objects.all().delete()
|
|
DomainRequest.objects.all().delete()
|
|
User.objects.all().delete()
|
|
DraftDomain.objects.all().delete()
|
|
|
|
@boto3_mocking.patching
|
|
@less_console_noise_decorator
|
|
def test_approval_creates_info(self):
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
|
user, _ = User.objects.get_or_create()
|
|
investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True)
|
|
domain_request = DomainRequest.objects.create(
|
|
creator=user, requested_domain=draft_domain, notes="test notes", investigator=investigator
|
|
)
|
|
|
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
|
# skip using the submit method
|
|
domain_request.status = DomainRequest.DomainRequestStatus.SUBMITTED
|
|
domain_request.approve()
|
|
|
|
# should be an information present for this domain
|
|
domain = Domain.objects.get(name="igorville.gov")
|
|
domain_information = DomainInformation.objects.filter(domain=domain)
|
|
self.assertTrue(domain_information.exists())
|
|
|
|
# Test that both objects are what we expect
|
|
current_domain_information = domain_information.get().__dict__
|
|
expected_domain_information = DomainInformation(
|
|
creator=user,
|
|
domain=domain,
|
|
notes="test notes",
|
|
domain_request=domain_request,
|
|
federal_agency=FederalAgency.objects.get(agency="Non-Federal Agency"),
|
|
).__dict__
|
|
|
|
# Test the two records for consistency
|
|
self.assertEqual(self.clean_dict(current_domain_information), self.clean_dict(expected_domain_information))
|
|
|
|
def clean_dict(self, dict_obj):
|
|
"""Cleans dynamic fields in a dictionary"""
|
|
bad_fields = ["_state", "created_at", "id", "updated_at"]
|
|
return {k: v for k, v in dict_obj.items() if k not in bad_fields}
|
|
|
|
|
|
class TestDomainInvitations(TestCase):
|
|
"""Test the retrieval of domain invitations."""
|
|
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
|
self.email = "mayor@igorville.gov"
|
|
self.invitation, _ = DomainInvitation.objects.get_or_create(email=self.email, domain=self.domain)
|
|
self.user, _ = User.objects.get_or_create(email=self.email)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
# clean out the roles each time
|
|
UserDomainRole.objects.all().delete()
|
|
self.domain.delete()
|
|
self.invitation.delete()
|
|
User.objects.all().delete()
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieval_creates_role(self):
|
|
self.invitation.retrieve()
|
|
self.assertTrue(UserDomainRole.objects.get(user=self.user, domain=self.domain))
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieve_missing_user_error(self):
|
|
# get rid of matching users
|
|
User.objects.filter(email=self.email).delete()
|
|
with self.assertRaises(RuntimeError):
|
|
self.invitation.retrieve()
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieve_existing_role_no_error(self):
|
|
# make the overlapping role
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
|
|
# this is not an error but does produce a console warning
|
|
self.invitation.retrieve()
|
|
self.assertEqual(self.invitation.status, DomainInvitation.DomainInvitationStatus.RETRIEVED)
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieve_on_each_login(self):
|
|
"""A user's authenticate on_each_login callback retrieves their invitations."""
|
|
self.user.on_each_login()
|
|
self.assertTrue(UserDomainRole.objects.get(user=self.user, domain=self.domain))
|
|
|
|
|
|
class TestPortfolioInvitations(TestCase):
|
|
"""Test the retrieval of portfolio invitations."""
|
|
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
self.email = "mayor@igorville.gov"
|
|
self.email2 = "creator@igorville.gov"
|
|
self.user, _ = User.objects.get_or_create(email=self.email)
|
|
self.user2, _ = User.objects.get_or_create(email=self.email2, username="creator")
|
|
self.portfolio, _ = Portfolio.objects.get_or_create(creator=self.user2, organization_name="Hotel California")
|
|
self.portfolio_role_base = UserPortfolioRoleChoices.ORGANIZATION_MEMBER
|
|
self.portfolio_role_admin = UserPortfolioRoleChoices.ORGANIZATION_ADMIN
|
|
self.portfolio_permission_1 = UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS
|
|
self.portfolio_permission_2 = UserPortfolioPermissionChoices.EDIT_REQUESTS
|
|
self.invitation, _ = PortfolioInvitation.objects.get_or_create(
|
|
email=self.email,
|
|
portfolio=self.portfolio,
|
|
portfolio_roles=[self.portfolio_role_base, self.portfolio_role_admin],
|
|
portfolio_additional_permissions=[self.portfolio_permission_1, self.portfolio_permission_2],
|
|
)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
Portfolio.objects.all().delete()
|
|
PortfolioInvitation.objects.all().delete()
|
|
User.objects.all().delete()
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieval(self):
|
|
self.assertFalse(self.user.portfolio)
|
|
self.invitation.retrieve()
|
|
self.user.refresh_from_db()
|
|
self.assertEqual(self.user.portfolio.organization_name, "Hotel California")
|
|
self.assertEqual(self.user.portfolio_roles, [self.portfolio_role_base, self.portfolio_role_admin])
|
|
self.assertEqual(
|
|
self.user.portfolio_additional_permissions, [self.portfolio_permission_1, self.portfolio_permission_2]
|
|
)
|
|
self.assertEqual(self.invitation.status, PortfolioInvitation.PortfolioInvitationStatus.RETRIEVED)
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieve_missing_user_error(self):
|
|
# get rid of matching users
|
|
User.objects.filter(email=self.email).delete()
|
|
with self.assertRaises(RuntimeError):
|
|
self.invitation.retrieve()
|
|
|
|
@less_console_noise_decorator
|
|
def test_retrieve_user_already_member_error(self):
|
|
self.assertFalse(self.user.portfolio)
|
|
portfolio2, _ = Portfolio.objects.get_or_create(creator=self.user2, organization_name="Tokyo Hotel")
|
|
self.user.portfolio = portfolio2
|
|
self.assertEqual(self.user.portfolio.organization_name, "Tokyo Hotel")
|
|
self.user.save()
|
|
self.user.check_portfolio_invitations_on_login()
|
|
self.user.refresh_from_db()
|
|
self.assertEqual(self.user.portfolio.organization_name, "Tokyo Hotel")
|
|
self.assertEqual(self.invitation.status, PortfolioInvitation.PortfolioInvitationStatus.INVITED)
|
|
|
|
|
|
class TestUser(TestCase):
|
|
"""Test actions that occur on user login,
|
|
test class method that controls how users get validated."""
|
|
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
self.email = "mayor@igorville.gov"
|
|
self.domain_name = "igorvilleInTransition.gov"
|
|
self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
|
self.user, _ = User.objects.get_or_create(email=self.email)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
Domain.objects.all().delete()
|
|
DomainInvitation.objects.all().delete()
|
|
DomainInformation.objects.all().delete()
|
|
DomainRequest.objects.all().delete()
|
|
DraftDomain.objects.all().delete()
|
|
TransitionDomain.objects.all().delete()
|
|
Portfolio.objects.all().delete()
|
|
User.objects.all().delete()
|
|
UserDomainRole.objects.all().delete()
|
|
|
|
@patch.object(User, "has_edit_suborganization", return_value=True)
|
|
def test_portfolio_role_summary_admin(self, mock_edit_suborganization):
|
|
# Test if the user is recognized as an Admin
|
|
self.assertEqual(self.user.portfolio_role_summary, ["Admin"])
|
|
|
|
@patch.multiple(
|
|
User,
|
|
has_view_all_domains_permission=lambda self: True,
|
|
has_domain_requests_portfolio_permission=lambda self: True,
|
|
has_edit_requests=lambda self: True,
|
|
)
|
|
def test_portfolio_role_summary_view_only_admin_and_domain_requestor(self):
|
|
# Test if the user has both 'View-only admin' and 'Domain requestor' roles
|
|
self.assertEqual(self.user.portfolio_role_summary, ["View-only admin", "Domain requestor"])
|
|
|
|
@patch.multiple(
|
|
User,
|
|
has_view_all_domains_permission=lambda self: True,
|
|
has_domain_requests_portfolio_permission=lambda self: True,
|
|
)
|
|
def test_portfolio_role_summary_view_only_admin(self):
|
|
# Test if the user is recognized as a View-only admin
|
|
self.assertEqual(self.user.portfolio_role_summary, ["View-only admin"])
|
|
|
|
@patch.multiple(
|
|
User,
|
|
has_base_portfolio_permission=lambda self: True,
|
|
has_edit_requests=lambda self: True,
|
|
has_domains_portfolio_permission=lambda self: True,
|
|
)
|
|
def test_portfolio_role_summary_member_domain_requestor_domain_manager(self):
|
|
# Test if the user has 'Member', 'Domain requestor', and 'Domain manager' roles
|
|
self.assertEqual(self.user.portfolio_role_summary, ["Domain requestor", "Domain manager"])
|
|
|
|
@patch.multiple(User, has_base_portfolio_permission=lambda self: True, has_edit_requests=lambda self: True)
|
|
def test_portfolio_role_summary_member_domain_requestor(self):
|
|
# Test if the user has 'Member' and 'Domain requestor' roles
|
|
self.assertEqual(self.user.portfolio_role_summary, ["Domain requestor"])
|
|
|
|
@patch.multiple(
|
|
User, has_base_portfolio_permission=lambda self: True, has_domains_portfolio_permission=lambda self: True
|
|
)
|
|
def test_portfolio_role_summary_member_domain_manager(self):
|
|
# Test if the user has 'Member' and 'Domain manager' roles
|
|
self.assertEqual(self.user.portfolio_role_summary, ["Domain manager"])
|
|
|
|
@patch.multiple(User, has_base_portfolio_permission=lambda self: True)
|
|
def test_portfolio_role_summary_member(self):
|
|
# Test if the user is recognized as a Member
|
|
self.assertEqual(self.user.portfolio_role_summary, ["Member"])
|
|
|
|
def test_portfolio_role_summary_empty(self):
|
|
# Test if the user has no roles
|
|
self.assertEqual(self.user.portfolio_role_summary, [])
|
|
|
|
@less_console_noise_decorator
|
|
def test_check_transition_domains_without_domains_on_login(self):
|
|
"""A user's on_each_login callback does not check transition domains.
|
|
This test makes sure that in the event a domain does not exist
|
|
for a given transition domain, both a domain and domain invitation
|
|
are created."""
|
|
self.user.on_each_login()
|
|
self.assertFalse(Domain.objects.filter(name=self.domain_name).exists())
|
|
|
|
@less_console_noise_decorator
|
|
def test_identity_verification_with_domain_manager(self):
|
|
"""A domain manager should return False when tested with class
|
|
method needs_identity_verification"""
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertFalse(User.needs_identity_verification(self.user.email, self.user.username))
|
|
|
|
@less_console_noise_decorator
|
|
def test_identity_verification_with_transition_user(self):
|
|
"""A user from the Verisign transition should return False
|
|
when tested with class method needs_identity_verification"""
|
|
TransitionDomain.objects.get_or_create(username=self.user.email, domain_name=self.domain_name)
|
|
self.assertFalse(User.needs_identity_verification(self.user.email, self.user.username))
|
|
|
|
@less_console_noise_decorator
|
|
def test_identity_verification_with_very_important_person(self):
|
|
"""A Very Important Person should return False
|
|
when tested with class method needs_identity_verification"""
|
|
VerifiedByStaff.objects.get_or_create(email=self.user.email)
|
|
self.assertFalse(User.needs_identity_verification(self.user.email, self.user.username))
|
|
|
|
@less_console_noise_decorator
|
|
def test_identity_verification_with_invited_user(self):
|
|
"""An invited user should return False when tested with class
|
|
method needs_identity_verification"""
|
|
DomainInvitation.objects.get_or_create(email=self.user.email, domain=self.domain)
|
|
self.assertFalse(User.needs_identity_verification(self.user.email, self.user.username))
|
|
|
|
@less_console_noise_decorator
|
|
def test_identity_verification_with_new_user(self):
|
|
"""A new user who's neither transitioned nor invited should
|
|
return True when tested with class method needs_identity_verification"""
|
|
self.assertTrue(User.needs_identity_verification(self.user.email, self.user.username))
|
|
|
|
@less_console_noise_decorator
|
|
def test_check_domain_invitations_on_login_caps_email(self):
|
|
"""A DomainInvitation with an email address with capital letters should match
|
|
a User record whose email address is not in caps"""
|
|
# create DomainInvitation with CAPS email that matches User email
|
|
# on a case-insensitive match
|
|
caps_email = "MAYOR@igorville.gov"
|
|
# mock the domain invitation save routine
|
|
with patch("registrar.models.DomainInvitation.save") as save_mock:
|
|
DomainInvitation.objects.get_or_create(email=caps_email, domain=self.domain)
|
|
self.user.check_domain_invitations_on_login()
|
|
# if check_domain_invitations_on_login properly matches exactly one
|
|
# Domain Invitation, then save routine should be called exactly once
|
|
save_mock.assert_called_once()
|
|
|
|
@less_console_noise_decorator
|
|
def test_approved_domains_count(self):
|
|
"""Test that the correct approved domain count is returned for a user"""
|
|
# with no associated approved domains, expect this to return 0
|
|
self.assertEquals(self.user.get_approved_domains_count(), 0)
|
|
# with one approved domain, expect this to return 1
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertEquals(self.user.get_approved_domains_count(), 1)
|
|
# with one approved domain, expect this to return 1 (domain2 is deleted, so not considered approved)
|
|
domain2, _ = Domain.objects.get_or_create(name="igorville2.gov", state=Domain.State.DELETED)
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain2, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertEquals(self.user.get_approved_domains_count(), 1)
|
|
# with two approved domains, expect this to return 2
|
|
domain3, _ = Domain.objects.get_or_create(name="igorville3.gov", state=Domain.State.DNS_NEEDED)
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain3, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertEquals(self.user.get_approved_domains_count(), 2)
|
|
# with three approved domains, expect this to return 3
|
|
domain4, _ = Domain.objects.get_or_create(name="igorville4.gov", state=Domain.State.ON_HOLD)
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain4, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertEquals(self.user.get_approved_domains_count(), 3)
|
|
# with four approved domains, expect this to return 4
|
|
domain5, _ = Domain.objects.get_or_create(name="igorville5.gov", state=Domain.State.READY)
|
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain5, role=UserDomainRole.Roles.MANAGER)
|
|
self.assertEquals(self.user.get_approved_domains_count(), 4)
|
|
|
|
@less_console_noise_decorator
|
|
def test_active_requests_count(self):
|
|
"""Test that the correct active domain requests count is returned for a user"""
|
|
# with no associated active requests, expect this to return 0
|
|
self.assertEquals(self.user.get_active_requests_count(), 0)
|
|
# with one active request, expect this to return 1
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.SUBMITTED
|
|
)
|
|
self.assertEquals(self.user.get_active_requests_count(), 1)
|
|
# with two active requests, expect this to return 2
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville2.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.IN_REVIEW
|
|
)
|
|
self.assertEquals(self.user.get_active_requests_count(), 2)
|
|
# with three active requests, expect this to return 3
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville3.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.ACTION_NEEDED
|
|
)
|
|
self.assertEquals(self.user.get_active_requests_count(), 3)
|
|
# with three active requests, expect this to return 3 (STARTED is not considered active)
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville4.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.STARTED
|
|
)
|
|
self.assertEquals(self.user.get_active_requests_count(), 3)
|
|
|
|
@less_console_noise_decorator
|
|
def test_rejected_requests_count(self):
|
|
"""Test that the correct rejected domain requests count is returned for a user"""
|
|
# with no associated rejected requests, expect this to return 0
|
|
self.assertEquals(self.user.get_rejected_requests_count(), 0)
|
|
# with one rejected request, expect this to return 1
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.REJECTED
|
|
)
|
|
self.assertEquals(self.user.get_rejected_requests_count(), 1)
|
|
|
|
@less_console_noise_decorator
|
|
def test_ineligible_requests_count(self):
|
|
"""Test that the correct ineligible domain requests count is returned for a user"""
|
|
# with no associated ineligible requests, expect this to return 0
|
|
self.assertEquals(self.user.get_ineligible_requests_count(), 0)
|
|
# with one ineligible request, expect this to return 1
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
|
DomainRequest.objects.create(
|
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.INELIGIBLE
|
|
)
|
|
self.assertEquals(self.user.get_ineligible_requests_count(), 1)
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_contact_info(self):
|
|
"""Test that has_contact_info properly returns"""
|
|
# test with a user with contact info defined
|
|
self.assertTrue(self.user.has_contact_info())
|
|
# test with a user without contact info defined
|
|
self.user.title = None
|
|
self.user.email = None
|
|
self.user.phone = None
|
|
self.assertFalse(self.user.has_contact_info())
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_portfolio_permission(self):
|
|
"""
|
|
0. Returns False when user does not have a permission
|
|
1. Returns False when a user does not have a portfolio
|
|
2. Returns True when user has direct permission
|
|
3. Returns True when user has permission through a role
|
|
|
|
Note: This tests _get_portfolio_permissions as a side effect
|
|
"""
|
|
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
|
|
|
|
self.user.portfolio_additional_permissions = [UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS]
|
|
self.user.save()
|
|
self.user.refresh_from_db()
|
|
|
|
user_can_view_all_domains = self.user.has_domains_portfolio_permission()
|
|
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission()
|
|
|
|
self.assertFalse(user_can_view_all_domains)
|
|
self.assertFalse(user_can_view_all_requests)
|
|
|
|
self.user.portfolio = portfolio
|
|
self.user.save()
|
|
self.user.refresh_from_db()
|
|
|
|
user_can_view_all_domains = self.user.has_domains_portfolio_permission()
|
|
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission()
|
|
|
|
self.assertTrue(user_can_view_all_domains)
|
|
self.assertFalse(user_can_view_all_requests)
|
|
|
|
self.user.portfolio_roles = [UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
|
self.user.save()
|
|
self.user.refresh_from_db()
|
|
|
|
user_can_view_all_domains = self.user.has_domains_portfolio_permission()
|
|
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission()
|
|
|
|
self.assertTrue(user_can_view_all_domains)
|
|
self.assertTrue(user_can_view_all_requests)
|
|
|
|
UserDomainRole.objects.all().get_or_create(
|
|
user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
|
|
)
|
|
|
|
user_can_view_all_domains = self.user.has_domains_portfolio_permission()
|
|
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission()
|
|
|
|
self.assertTrue(user_can_view_all_domains)
|
|
self.assertTrue(user_can_view_all_requests)
|
|
|
|
Portfolio.objects.all().delete()
|
|
|
|
@less_console_noise_decorator
|
|
def test_user_with_portfolio_but_no_roles(self):
|
|
# Create an instance of User with a portfolio but no roles or additional permissions
|
|
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
|
|
|
|
self.user.portfolio = portfolio
|
|
self.user.portfolio_roles = []
|
|
|
|
# Test if the ValidationError is raised with the correct message
|
|
with self.assertRaises(ValidationError) as cm:
|
|
self.user.clean()
|
|
|
|
self.assertEqual(
|
|
cm.exception.message, "When portfolio is assigned, portfolio roles or additional permissions are required."
|
|
)
|
|
Portfolio.objects.all().delete()
|
|
|
|
@less_console_noise_decorator
|
|
def test_user_with_portfolio_roles_but_no_portfolio(self):
|
|
# Create an instance of User with a portfolio role but no portfolio
|
|
self.user.portfolio = None
|
|
self.user.portfolio_roles = [UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
|
|
|
# Test if the ValidationError is raised with the correct message
|
|
with self.assertRaises(ValidationError) as cm:
|
|
self.user.clean()
|
|
|
|
self.assertEqual(
|
|
cm.exception.message, "When portfolio roles or additional permissions are assigned, portfolio is required."
|
|
)
|
|
|
|
|
|
class TestContact(TestCase):
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
self.email = "mayor@igorville.gov"
|
|
self.user, _ = User.objects.get_or_create(
|
|
email=self.email, first_name="Jeff", last_name="Lebowski", phone="123456789"
|
|
)
|
|
self.contact, _ = Contact.objects.get_or_create(
|
|
first_name="Jeff",
|
|
last_name="Lebowski",
|
|
)
|
|
|
|
self.contact_as_so, _ = Contact.objects.get_or_create(email="newguy@igorville.gov")
|
|
self.domain_request = DomainRequest.objects.create(creator=self.user, senior_official=self.contact_as_so)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
DomainRequest.objects.all().delete()
|
|
Contact.objects.all().delete()
|
|
User.objects.all().delete()
|
|
|
|
def test_has_more_than_one_join(self):
|
|
"""Test the Contact model method, has_more_than_one_join"""
|
|
# test for a contact which is assigned as a senior official on a domain request
|
|
self.assertFalse(self.contact_as_so.has_more_than_one_join("senior_official"))
|
|
self.assertTrue(self.contact_as_so.has_more_than_one_join("submitted_domain_requests"))
|
|
|
|
@less_console_noise_decorator
|
|
def test_has_contact_info(self):
|
|
"""Test that has_contact_info properly returns"""
|
|
self.contact.title = "Title"
|
|
# test with a contact with contact info defined
|
|
self.assertTrue(self.contact.has_contact_info())
|
|
# test with a contact without contact info defined
|
|
self.contact.title = None
|
|
self.contact.email = None
|
|
self.contact.phone = None
|
|
self.assertFalse(self.contact.has_contact_info())
|
|
|
|
|
|
class TestDomainRequestCustomSave(TestCase):
|
|
"""Tests custom save behaviour on the DomainRequest object"""
|
|
|
|
def tearDown(self):
|
|
DomainRequest.objects.all().delete()
|
|
super().tearDown()
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_new_instance(self):
|
|
"""Test create_or_update_organization_type when creating a new instance"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
)
|
|
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_new_instance_federal_does_nothing(self):
|
|
"""Test if create_or_update_organization_type does nothing when creating a new instance for federal"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
|
is_election_board=True,
|
|
)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.FEDERAL)
|
|
self.assertEqual(domain_request.is_election_board, None)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_existing_instance_updates_election_board(self):
|
|
"""Test create_or_update_organization_type for an existing instance."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=False,
|
|
)
|
|
domain_request.is_election_board = True
|
|
domain_request.save()
|
|
|
|
self.assertEqual(domain_request.is_election_board, True)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
# Try reverting the election board value
|
|
domain_request.is_election_board = False
|
|
domain_request.save()
|
|
|
|
self.assertEqual(domain_request.is_election_board, False)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
|
|
@less_console_noise_decorator
|
|
def test_existing_instance_updates_election_board_to_none(self):
|
|
"""Test create_or_update_organization_type for an existing instance, first to True and then to None.
|
|
Start our with is_election_board as none to simulate a situation where the request was started, but
|
|
only completed to the point of filling out the generic_org_type."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=None,
|
|
)
|
|
domain_request.is_election_board = True
|
|
domain_request.save()
|
|
|
|
self.assertEqual(domain_request.is_election_board, True)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
# Try reverting the election board value.
|
|
domain_request.is_election_board = None
|
|
domain_request.save()
|
|
|
|
self.assertEqual(domain_request.is_election_board, None)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_existing_instance_updates_generic_org_type(self):
|
|
"""Test create_or_update_organization_type when modifying generic_org_type on an existing instance."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
)
|
|
|
|
domain_request.generic_org_type = DomainRequest.OrganizationChoices.INTERSTATE
|
|
domain_request.save()
|
|
|
|
# Election board should be None because interstate cannot have an election board.
|
|
self.assertEqual(domain_request.is_election_board, None)
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.INTERSTATE)
|
|
|
|
# Try changing the org Type to something that CAN have an election board.
|
|
domain_request_tribal = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="startedTribal.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.TRIBAL,
|
|
is_election_board=True,
|
|
)
|
|
self.assertEqual(
|
|
domain_request_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.TRIBAL_ELECTION
|
|
)
|
|
|
|
# Change the org type
|
|
domain_request_tribal.generic_org_type = DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
|
|
domain_request_tribal.save()
|
|
|
|
self.assertEqual(domain_request_tribal.is_election_board, True)
|
|
self.assertEqual(
|
|
domain_request_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.STATE_OR_TERRITORY_ELECTION
|
|
)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_no_update(self):
|
|
"""Test create_or_update_organization_type when there are no values to update."""
|
|
|
|
# Test for when both generic_org_type and organization_type is declared,
|
|
# and are both non-election board
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=False,
|
|
)
|
|
domain_request.save()
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
self.assertEqual(domain_request.is_election_board, False)
|
|
self.assertEqual(domain_request.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Test for when both generic_org_type and organization_type is declared,
|
|
# and are both election board
|
|
domain_request_election = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="startedElection.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
organization_type=DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION,
|
|
)
|
|
|
|
self.assertEqual(
|
|
domain_request_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
|
)
|
|
self.assertEqual(domain_request_election.is_election_board, True)
|
|
self.assertEqual(domain_request_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Modify an unrelated existing value for both, and ensure that everything is still consistent
|
|
domain_request.city = "Fudge"
|
|
domain_request_election.city = "Caramel"
|
|
domain_request.save()
|
|
domain_request_election.save()
|
|
|
|
self.assertEqual(domain_request.city, "Fudge")
|
|
self.assertEqual(domain_request_election.city, "Caramel")
|
|
|
|
# Test for non-election
|
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
self.assertEqual(domain_request.is_election_board, False)
|
|
self.assertEqual(domain_request.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Test for election
|
|
self.assertEqual(
|
|
domain_request_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
|
)
|
|
self.assertEqual(domain_request_election.is_election_board, True)
|
|
self.assertEqual(domain_request_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
|
|
class TestDomainInformationCustomSave(TestCase):
|
|
"""Tests custom save behaviour on the DomainInformation object"""
|
|
|
|
def tearDown(self):
|
|
DomainInformation.objects.all().delete()
|
|
DomainRequest.objects.all().delete()
|
|
Domain.objects.all().delete()
|
|
super().tearDown()
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_new_instance(self):
|
|
"""Test create_or_update_organization_type when creating a new instance"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
)
|
|
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_new_instance_federal_does_nothing(self):
|
|
"""Test if create_or_update_organization_type does nothing when creating a new instance for federal"""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
|
is_election_board=True,
|
|
)
|
|
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.FEDERAL)
|
|
self.assertEqual(domain_information.is_election_board, None)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_existing_instance_updates_election_board(self):
|
|
"""Test create_or_update_organization_type for an existing instance."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=False,
|
|
)
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
domain_information.is_election_board = True
|
|
domain_information.save()
|
|
|
|
self.assertEqual(domain_information.is_election_board, True)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
# Try reverting the election board value
|
|
domain_information.is_election_board = False
|
|
domain_information.save()
|
|
domain_information.refresh_from_db()
|
|
|
|
self.assertEqual(domain_information.is_election_board, False)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
|
|
@less_console_noise_decorator
|
|
def test_existing_instance_update_election_board_to_none(self):
|
|
"""Test create_or_update_organization_type for an existing instance, first to True and then to None.
|
|
Start our with is_election_board as none to simulate a situation where the request was started, but
|
|
only completed to the point of filling out the generic_org_type."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=None,
|
|
)
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
domain_information.is_election_board = True
|
|
domain_information.save()
|
|
|
|
self.assertEqual(domain_information.is_election_board, True)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
|
|
|
# Try reverting the election board value
|
|
domain_information.is_election_board = None
|
|
domain_information.save()
|
|
domain_information.refresh_from_db()
|
|
|
|
self.assertEqual(domain_information.is_election_board, None)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_existing_instance_updates_generic_org_type(self):
|
|
"""Test create_or_update_organization_type when modifying generic_org_type on an existing instance."""
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
)
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
|
|
domain_information.generic_org_type = DomainRequest.OrganizationChoices.INTERSTATE
|
|
domain_information.save()
|
|
|
|
# Election board should be None because interstate cannot have an election board.
|
|
self.assertEqual(domain_information.is_election_board, None)
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.INTERSTATE)
|
|
|
|
# Try changing the org Type to something that CAN have an election board.
|
|
domain_request_tribal = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="startedTribal.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.TRIBAL,
|
|
is_election_board=True,
|
|
)
|
|
domain_information_tribal = DomainInformation.create_from_da(domain_request_tribal)
|
|
self.assertEqual(
|
|
domain_information_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.TRIBAL_ELECTION
|
|
)
|
|
|
|
# Change the org type
|
|
domain_information_tribal.generic_org_type = DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
|
|
domain_information_tribal.save()
|
|
|
|
self.assertEqual(domain_information_tribal.is_election_board, True)
|
|
self.assertEqual(
|
|
domain_information_tribal.organization_type,
|
|
DomainRequest.OrgChoicesElectionOffice.STATE_OR_TERRITORY_ELECTION,
|
|
)
|
|
|
|
@less_console_noise_decorator
|
|
def test_create_or_update_organization_type_no_update(self):
|
|
"""Test create_or_update_organization_type when there are no values to update."""
|
|
|
|
# Test for when both generic_org_type and organization_type is declared,
|
|
# and are both non-election board
|
|
domain_request = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="started.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=False,
|
|
)
|
|
domain_information = DomainInformation.create_from_da(domain_request)
|
|
domain_information.save()
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
self.assertEqual(domain_information.is_election_board, False)
|
|
self.assertEqual(domain_information.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Test for when both generic_org_type and organization_type is declared,
|
|
# and are both election board
|
|
domain_request_election = completed_domain_request(
|
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
|
name="startedElection.gov",
|
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
|
is_election_board=True,
|
|
organization_type=DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION,
|
|
)
|
|
domain_information_election = DomainInformation.create_from_da(domain_request_election)
|
|
|
|
self.assertEqual(
|
|
domain_information_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
|
)
|
|
self.assertEqual(domain_information_election.is_election_board, True)
|
|
self.assertEqual(domain_information_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Modify an unrelated existing value for both, and ensure that everything is still consistent
|
|
domain_information.city = "Fudge"
|
|
domain_information_election.city = "Caramel"
|
|
domain_information.save()
|
|
domain_information_election.save()
|
|
|
|
self.assertEqual(domain_information.city, "Fudge")
|
|
self.assertEqual(domain_information_election.city, "Caramel")
|
|
|
|
# Test for non-election
|
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
|
self.assertEqual(domain_information.is_election_board, False)
|
|
self.assertEqual(domain_information.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
# Test for election
|
|
self.assertEqual(
|
|
domain_information_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
|
)
|
|
self.assertEqual(domain_information_election.is_election_board, True)
|
|
self.assertEqual(domain_information_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
|
|
|
|
|
class TestDomainRequestIncomplete(TestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.factory = RequestFactory()
|
|
cls.user = create_test_user()
|
|
|
|
@less_console_noise_decorator
|
|
def setUp(self):
|
|
super().setUp()
|
|
so, _ = Contact.objects.get_or_create(
|
|
first_name="Meowy",
|
|
last_name="Meoward",
|
|
title="Chief Cat",
|
|
email="meoward@chiefcat.com",
|
|
phone="(206) 206 2060",
|
|
)
|
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="MeowardMeowardMeoward.gov")
|
|
you, _ = Contact.objects.get_or_create(
|
|
first_name="Testy you",
|
|
last_name="Tester you",
|
|
title="Admin Tester",
|
|
email="testy-admin@town.com",
|
|
phone="(555) 555 5556",
|
|
)
|
|
other, _ = Contact.objects.get_or_create(
|
|
first_name="Testy2",
|
|
last_name="Tester2",
|
|
title="Another Tester",
|
|
email="testy2@town.com",
|
|
phone="(555) 555 5557",
|
|
)
|
|
alt, _ = Website.objects.get_or_create(website="MeowardMeowardMeoward1.gov")
|
|
current, _ = Website.objects.get_or_create(website="MeowardMeowardMeoward.com")
|
|
self.amtrak, _ = FederalAgency.objects.get_or_create(agency="AMTRAK")
|
|
self.domain_request = DomainRequest.objects.create(
|
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
|
federal_type="executive",
|
|
federal_agency=FederalAgency.objects.get(agency="AMTRAK"),
|
|
about_your_organization="Some description",
|
|
is_election_board=True,
|
|
tribe_name="Some tribe name",
|
|
organization_name="Some organization",
|
|
address_line1="address 1",
|
|
state_territory="CA",
|
|
zipcode="94044",
|
|
senior_official=so,
|
|
requested_domain=draft_domain,
|
|
purpose="Some purpose",
|
|
submitter=you,
|
|
no_other_contacts_rationale=None,
|
|
has_cisa_representative=True,
|
|
cisa_representative_email="somerep@cisa.com",
|
|
has_anything_else_text=True,
|
|
anything_else="Anything else",
|
|
is_policy_acknowledged=True,
|
|
creator=self.user,
|
|
)
|
|
|
|
self.domain_request.other_contacts.add(other)
|
|
self.domain_request.current_websites.add(current)
|
|
self.domain_request.alternative_domains.add(alt)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
DomainRequest.objects.all().delete()
|
|
Contact.objects.all().delete()
|
|
self.amtrak.delete()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
super().tearDownClass()
|
|
cls.user.delete()
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_federal_complete(self):
|
|
self.assertTrue(self.domain_request._is_federal_complete())
|
|
self.domain_request.federal_type = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_federal_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_interstate_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.INTERSTATE
|
|
self.domain_request.about_your_organization = "Something something about your organization"
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_interstate_complete())
|
|
self.domain_request.about_your_organization = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_interstate_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_state_or_territory_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
|
|
self.domain_request.is_election_board = True
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_state_or_territory_complete())
|
|
self.domain_request.is_election_board = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_state_or_territory_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_tribal_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.TRIBAL
|
|
self.domain_request.tribe_name = "Tribe Name"
|
|
self.domain_request.is_election_board = False
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_tribal_complete())
|
|
self.domain_request.is_election_board = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_tribal_complete())
|
|
self.domain_request.tribe_name = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_tribal_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_county_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.COUNTY
|
|
self.domain_request.is_election_board = False
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_county_complete())
|
|
self.domain_request.is_election_board = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_county_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_city_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.CITY
|
|
self.domain_request.is_election_board = False
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_city_complete())
|
|
self.domain_request.is_election_board = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_city_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_special_district_complete(self):
|
|
self.domain_request.generic_org_type = DomainRequest.OrganizationChoices.SPECIAL_DISTRICT
|
|
self.domain_request.about_your_organization = "Something something about your organization"
|
|
self.domain_request.is_election_board = False
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_special_district_complete())
|
|
self.domain_request.is_election_board = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_special_district_complete())
|
|
self.domain_request.about_your_organization = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_special_district_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_organization_name_and_address_complete(self):
|
|
self.assertTrue(self.domain_request._is_organization_name_and_address_complete())
|
|
self.domain_request.organization_name = None
|
|
self.domain_request.address_line1 = None
|
|
self.domain_request.save()
|
|
self.assertTrue(self.domain_request._is_organization_name_and_address_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_senior_official_complete(self):
|
|
self.assertTrue(self.domain_request._is_senior_official_complete())
|
|
self.domain_request.senior_official = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_senior_official_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_requested_domain_complete(self):
|
|
self.assertTrue(self.domain_request._is_requested_domain_complete())
|
|
self.domain_request.requested_domain = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_requested_domain_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_purpose_complete(self):
|
|
self.assertTrue(self.domain_request._is_purpose_complete())
|
|
self.domain_request.purpose = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_purpose_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_submitter_complete(self):
|
|
self.assertTrue(self.domain_request._is_submitter_complete())
|
|
self.domain_request.submitter = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._is_submitter_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_other_contacts_complete_missing_one_field(self):
|
|
self.assertTrue(self.domain_request._is_other_contacts_complete())
|
|
contact = self.domain_request.other_contacts.first()
|
|
contact.first_name = None
|
|
contact.save()
|
|
self.assertFalse(self.domain_request._is_other_contacts_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_other_contacts_complete_all_none(self):
|
|
self.domain_request.other_contacts.clear()
|
|
self.assertFalse(self.domain_request._is_other_contacts_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_other_contacts_False_and_has_rationale(self):
|
|
# Click radio button "No" for no other contacts and give rationale
|
|
self.domain_request.other_contacts.clear()
|
|
self.domain_request.other_contacts.exists = False
|
|
self.domain_request.no_other_contacts_rationale = "Some rationale"
|
|
self.assertTrue(self.domain_request._is_other_contacts_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_other_contacts_False_and_NO_rationale(self):
|
|
# Click radio button "No" for no other contacts and DONT give rationale
|
|
self.domain_request.other_contacts.clear()
|
|
self.domain_request.other_contacts.exists = False
|
|
self.domain_request.no_other_contacts_rationale = None
|
|
self.assertFalse(self.domain_request._is_other_contacts_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_additional_details_complete(self):
|
|
test_cases = [
|
|
# CISA Rep - Yes
|
|
# Firstname - Yes
|
|
# Lastname - Yes
|
|
# Email - Yes
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - Yes
|
|
{
|
|
"has_cisa_representative": True,
|
|
"cisa_representative_first_name": "cisa-first-name",
|
|
"cisa_representative_last_name": "cisa-last-name",
|
|
"cisa_representative_email": "some@cisarepemail.com",
|
|
"has_anything_else_text": True,
|
|
"anything_else": "Some text",
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - Yes
|
|
# Lastname - Yes
|
|
# Email - Yes
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - None
|
|
{
|
|
"has_cisa_representative": True,
|
|
"cisa_representative_first_name": "cisa-first-name",
|
|
"cisa_representative_last_name": "cisa-last-name",
|
|
"cisa_representative_email": "some@cisarepemail.com",
|
|
"has_anything_else_text": True,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - Yes
|
|
# Lastname - Yes
|
|
# Email - None >> e-mail is optional so it should not change anything setting this to None
|
|
# Anything Else Radio - No
|
|
# Anything Else Text - No
|
|
{
|
|
"has_cisa_representative": True,
|
|
"cisa_representative_first_name": "cisa-first-name",
|
|
"cisa_representative_last_name": "cisa-last-name",
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": False,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - Yes
|
|
# Lastname - Yes
|
|
# Email - None
|
|
# Anything Else Radio - None
|
|
# Anything Else Text - None
|
|
{
|
|
"has_cisa_representative": True,
|
|
"cisa_representative_first_name": "cisa-first-name",
|
|
"cisa_representative_last_name": "cisa-last-name",
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": None,
|
|
"anything_else": None,
|
|
"expected": False,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - None
|
|
# Lastname - None
|
|
# Email - None
|
|
# Anything Else Radio - None
|
|
# Anything Else Text - None
|
|
{
|
|
"has_cisa_representative": True,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": None,
|
|
"anything_else": None,
|
|
"expected": False,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - None
|
|
# Lastname - None
|
|
# Email - None
|
|
# Anything Else Radio - No
|
|
# Anything Else Text - No
|
|
# sync_yes_no will override has_cisa_representative to be False if cisa_representative_first_name is None
|
|
# therefore, our expected will be True
|
|
{
|
|
"has_cisa_representative": True,
|
|
# Above will be overridden to False if cisa_representative_first_name is None
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": False,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - None
|
|
# Lastname - None
|
|
# Email - None
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - None
|
|
# NOTE: We should never have an instance where only firstname or only lastname are populated
|
|
# (they are both required)
|
|
{
|
|
"has_cisa_representative": True,
|
|
# Above will be overridden to False if cisa_representative_first_name is None or
|
|
# cisa_representative_last_name is None bc of sync_yes_no_form_fields
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": True,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - Yes
|
|
# Firstname - None
|
|
# Lastname - None
|
|
# Email - None
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - Yes
|
|
{
|
|
"has_cisa_representative": True,
|
|
# Above will be overridden to False if cisa_representative_first_name is None or
|
|
# cisa_representative_last_name is None bc of sync_yes_no_form_fields
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": True,
|
|
"anything_else": "Some text",
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - No
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - Yes
|
|
{
|
|
"has_cisa_representative": False,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": True,
|
|
"anything_else": "Some text",
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - No
|
|
# Anything Else Radio - Yes
|
|
# Anything Else Text - None
|
|
{
|
|
"has_cisa_representative": False,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": True,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - No
|
|
# Anything Else Radio - None
|
|
# Anything Else Text - None
|
|
{
|
|
"has_cisa_representative": False,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": None,
|
|
"anything_else": None,
|
|
# Above is both None, so it does NOT get overwritten
|
|
"expected": False,
|
|
},
|
|
# CISA Rep - No
|
|
# Anything Else Radio - No
|
|
# Anything Else Text - No
|
|
{
|
|
"has_cisa_representative": False,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": False,
|
|
"anything_else": None,
|
|
"expected": True,
|
|
},
|
|
# CISA Rep - None
|
|
# Anything Else Radio - None
|
|
{
|
|
"has_cisa_representative": None,
|
|
"cisa_representative_first_name": None,
|
|
"cisa_representative_last_name": None,
|
|
"cisa_representative_email": None,
|
|
"has_anything_else_text": None,
|
|
"anything_else": None,
|
|
"expected": False,
|
|
},
|
|
]
|
|
for case in test_cases:
|
|
with self.subTest(case=case):
|
|
self.domain_request.has_cisa_representative = case["has_cisa_representative"]
|
|
self.domain_request.cisa_representative_email = case["cisa_representative_email"]
|
|
self.domain_request.has_anything_else_text = case["has_anything_else_text"]
|
|
self.domain_request.anything_else = case["anything_else"]
|
|
self.domain_request.save()
|
|
self.domain_request.refresh_from_db()
|
|
self.assertEqual(
|
|
self.domain_request._is_additional_details_complete(),
|
|
case["expected"],
|
|
msg=f"Failed for case: {case}",
|
|
)
|
|
|
|
@less_console_noise_decorator
|
|
def test_is_policy_acknowledgement_complete(self):
|
|
self.assertTrue(self.domain_request._is_policy_acknowledgement_complete())
|
|
self.domain_request.is_policy_acknowledged = False
|
|
self.assertTrue(self.domain_request._is_policy_acknowledgement_complete())
|
|
self.domain_request.is_policy_acknowledged = None
|
|
self.assertFalse(self.domain_request._is_policy_acknowledgement_complete())
|
|
|
|
@less_console_noise_decorator
|
|
def test_form_complete(self):
|
|
request = self.factory.get("/")
|
|
request.user = self.user
|
|
|
|
self.assertTrue(self.domain_request._form_complete(request))
|
|
self.domain_request.generic_org_type = None
|
|
self.domain_request.save()
|
|
self.assertFalse(self.domain_request._form_complete(request))
|
|
|
|
|
|
class TestPortfolio(TestCase):
|
|
def setUp(self):
|
|
self.user, _ = User.objects.get_or_create(
|
|
username="intern@igorville.com", email="intern@igorville.com", first_name="Lava", last_name="World"
|
|
)
|
|
super().setUp()
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
Portfolio.objects.all().delete()
|
|
User.objects.all().delete()
|
|
|
|
def test_urbanization_field_resets_when_not_puetro_rico(self):
|
|
"""The urbanization field should only be populated when the state is puetro rico.
|
|
Otherwise, this field should be empty."""
|
|
# Start out as PR, then change the field
|
|
portfolio = Portfolio.objects.create(
|
|
creator=self.user,
|
|
organization_name="Test Portfolio",
|
|
state_territory=DomainRequest.StateTerritoryChoices.PUERTO_RICO,
|
|
urbanization="test",
|
|
)
|
|
|
|
self.assertEqual(portfolio.urbanization, "test")
|
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
|
|
|
|
portfolio.state_territory = DomainRequest.StateTerritoryChoices.ALABAMA
|
|
portfolio.save()
|
|
|
|
self.assertEqual(portfolio.urbanization, None)
|
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
|
|
|
|
def test_can_add_urbanization_field(self):
|
|
"""Ensures that you can populate the urbanization field when conditions are right"""
|
|
# Create a portfolio that cannot have this field
|
|
portfolio = Portfolio.objects.create(
|
|
creator=self.user,
|
|
organization_name="Test Portfolio",
|
|
state_territory=DomainRequest.StateTerritoryChoices.ALABAMA,
|
|
urbanization="test",
|
|
)
|
|
|
|
# Implicitly check if this gets cleared on create. It should.
|
|
self.assertEqual(portfolio.urbanization, None)
|
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
|
|
|
|
portfolio.state_territory = DomainRequest.StateTerritoryChoices.PUERTO_RICO
|
|
portfolio.urbanization = "test123"
|
|
portfolio.save()
|
|
|
|
self.assertEqual(portfolio.urbanization, "test123")
|
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
|