+ {% block messages %}
+ {% include "includes/form_messages.html" %}
+ {% endblock %}
Manage your domains
diff --git a/src/registrar/templates/includes/form_messages.html b/src/registrar/templates/includes/form_messages.html
index c7b704f67..59ecb4eaa 100644
--- a/src/registrar/templates/includes/form_messages.html
+++ b/src/registrar/templates/includes/form_messages.html
@@ -2,7 +2,7 @@
{% for message in messages %}
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 023e5319e..2865bf5c5 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -12,6 +12,7 @@ from typing import List, Dict
from django.contrib.sessions.middleware import SessionMiddleware
from django.conf import settings
from django.contrib.auth import get_user_model, login
+from django.utils.timezone import make_aware
from registrar.models import (
Contact,
@@ -643,7 +644,7 @@ class MockEppLib(TestCase):
self,
id,
email,
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
pw="thisisnotapassword",
):
fake = info.InfoContactResultData(
@@ -681,7 +682,7 @@ class MockEppLib(TestCase):
mockDataInfoDomain = fakedEppObject(
"fakePw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
hosts=["fake.host.com"],
statuses=[
@@ -692,7 +693,7 @@ class MockEppLib(TestCase):
)
mockDataExtensionDomain = fakedEppObject(
"fakePw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
hosts=["fake.host.com"],
statuses=[
@@ -706,7 +707,7 @@ class MockEppLib(TestCase):
)
InfoDomainWithContacts = fakedEppObject(
"fakepw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="securityContact",
@@ -731,7 +732,7 @@ class MockEppLib(TestCase):
InfoDomainWithDefaultSecurityContact = fakedEppObject(
"fakepw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="defaultSec",
@@ -750,7 +751,7 @@ class MockEppLib(TestCase):
)
InfoDomainWithVerisignSecurityContact = fakedEppObject(
"fakepw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="defaultVeri",
@@ -766,7 +767,7 @@ class MockEppLib(TestCase):
InfoDomainWithDefaultTechnicalContact = fakedEppObject(
"fakepw",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="defaultTech",
@@ -791,14 +792,14 @@ class MockEppLib(TestCase):
infoDomainNoContact = fakedEppObject(
"security",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[],
hosts=["fake.host.com"],
)
infoDomainThreeHosts = fakedEppObject(
"my-nameserver.gov",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[],
hosts=[
"ns1.my-nameserver-1.com",
@@ -809,25 +810,25 @@ class MockEppLib(TestCase):
infoDomainNoHost = fakedEppObject(
"my-nameserver.gov",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[],
hosts=[],
)
infoDomainTwoHosts = fakedEppObject(
"my-nameserver.gov",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[],
hosts=["ns1.my-nameserver-1.com", "ns1.my-nameserver-2.com"],
)
mockDataInfoHosts = fakedEppObject(
"lastPw",
- cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 8, 25, 19, 45, 35)),
addrs=[common.Ip(addr="1.2.3.4"), common.Ip(addr="2.3.4.5")],
)
- mockDataHostChange = fakedEppObject("lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35))
+ mockDataHostChange = fakedEppObject("lastPw", cr_date=make_aware(datetime.datetime(2023, 8, 25, 19, 45, 35)))
addDsData1 = {
"keyTag": 1234,
"alg": 3,
@@ -859,7 +860,7 @@ class MockEppLib(TestCase):
infoDomainHasIP = fakedEppObject(
"nameserverwithip.gov",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="securityContact",
@@ -884,7 +885,7 @@ class MockEppLib(TestCase):
justNameserver = fakedEppObject(
"justnameserver.com",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[
common.DomainContact(
contact="securityContact",
@@ -907,7 +908,7 @@ class MockEppLib(TestCase):
infoDomainCheckHostIPCombo = fakedEppObject(
"nameserversubdomain.gov",
- cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
+ cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
contacts=[],
hosts=[
"ns1.nameserversubdomain.gov",
diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py
index f88e25c2f..86cc287e8 100644
--- a/src/registrar/tests/test_admin.py
+++ b/src/registrar/tests/test_admin.py
@@ -59,22 +59,22 @@ class TestDomainAdmin(MockEppLib):
"""
Make sure the short name is displaying in admin on the list page
"""
- self.client.force_login(self.superuser)
- application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW)
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
+ with less_console_noise():
+ self.client.force_login(self.superuser)
+ application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW)
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
application.approve()
- response = self.client.get("/admin/registrar/domain/")
+ response = self.client.get("/admin/registrar/domain/")
- # There are 3 template references to Federal (3) plus one reference in the table
- # for our actual application
- self.assertContains(response, "Federal", count=4)
- # This may be a bit more robust
- self.assertContains(response, '
Federal ', count=1)
- # Now let's make sure the long description does not exist
- self.assertNotContains(response, "Federal: an agency of the U.S. government")
+ # There are 3 template references to Federal (3) plus one reference in the table
+ # for our actual application
+ self.assertContains(response, "Federal", count=4)
+ # This may be a bit more robust
+ self.assertContains(response, '
Federal ', count=1)
+ # Now let's make sure the long description does not exist
+ self.assertNotContains(response, "Federal: an agency of the U.S. government")
@skip("Why did this test stop working, and is is a good test")
def test_place_and_remove_hold(self):
@@ -120,40 +120,37 @@ class TestDomainAdmin(MockEppLib):
Then a user-friendly success message is returned for displaying on the web
And `state` is et to `DELETED`
"""
- domain = create_ready_domain()
- # Put in client hold
- domain.place_client_hold()
- p = "userpass"
- self.client.login(username="staffuser", password=p)
-
- # Ensure everything is displaying correctly
- response = self.client.get(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- follow=True,
- )
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, domain.name)
- self.assertContains(response, "Remove from registry")
-
- # Test the info dialog
- request = self.factory.post(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- {"_delete_domain": "Remove from registry", "name": domain.name},
- follow=True,
- )
- request.user = self.client
-
- with patch("django.contrib.messages.add_message") as mock_add_message:
- self.admin.do_delete_domain(request, domain)
- mock_add_message.assert_called_once_with(
- request,
- messages.INFO,
- "Domain city.gov has been deleted. Thanks!",
- extra_tags="",
- fail_silently=False,
+ with less_console_noise():
+ domain = create_ready_domain()
+ # Put in client hold
+ domain.place_client_hold()
+ p = "userpass"
+ self.client.login(username="staffuser", password=p)
+ # Ensure everything is displaying correctly
+ response = self.client.get(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ follow=True,
)
-
- self.assertEqual(domain.state, Domain.State.DELETED)
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, domain.name)
+ self.assertContains(response, "Remove from registry")
+ # Test the info dialog
+ request = self.factory.post(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ {"_delete_domain": "Remove from registry", "name": domain.name},
+ follow=True,
+ )
+ request.user = self.client
+ with patch("django.contrib.messages.add_message") as mock_add_message:
+ self.admin.do_delete_domain(request, domain)
+ mock_add_message.assert_called_once_with(
+ request,
+ messages.INFO,
+ "Domain city.gov has been deleted. Thanks!",
+ extra_tags="",
+ fail_silently=False,
+ )
+ self.assertEqual(domain.state, Domain.State.DELETED)
def test_deletion_ready_fsm_failure(self):
"""
@@ -162,38 +159,36 @@ class TestDomainAdmin(MockEppLib):
Then a user-friendly error message is returned for displaying on the web
And `state` is not set to `DELETED`
"""
- domain = create_ready_domain()
- p = "userpass"
- self.client.login(username="staffuser", password=p)
-
- # Ensure everything is displaying correctly
- response = self.client.get(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- follow=True,
- )
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, domain.name)
- self.assertContains(response, "Remove from registry")
-
- # Test the error
- request = self.factory.post(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- {"_delete_domain": "Remove from registry", "name": domain.name},
- follow=True,
- )
- request.user = self.client
-
- with patch("django.contrib.messages.add_message") as mock_add_message:
- self.admin.do_delete_domain(request, domain)
- mock_add_message.assert_called_once_with(
- request,
- messages.ERROR,
- "Error deleting this Domain: "
- "Can't switch from state 'ready' to 'deleted'"
- ", must be either 'dns_needed' or 'on_hold'",
- extra_tags="",
- fail_silently=False,
+ with less_console_noise():
+ domain = create_ready_domain()
+ p = "userpass"
+ self.client.login(username="staffuser", password=p)
+ # Ensure everything is displaying correctly
+ response = self.client.get(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ follow=True,
)
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, domain.name)
+ self.assertContains(response, "Remove from registry")
+ # Test the error
+ request = self.factory.post(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ {"_delete_domain": "Remove from registry", "name": domain.name},
+ follow=True,
+ )
+ request.user = self.client
+ with patch("django.contrib.messages.add_message") as mock_add_message:
+ self.admin.do_delete_domain(request, domain)
+ mock_add_message.assert_called_once_with(
+ request,
+ messages.ERROR,
+ "Error deleting this Domain: "
+ "Can't switch from state 'ready' to 'deleted'"
+ ", must be either 'dns_needed' or 'on_hold'",
+ extra_tags="",
+ fail_silently=False,
+ )
self.assertEqual(domain.state, Domain.State.READY)
@@ -205,62 +200,57 @@ class TestDomainAdmin(MockEppLib):
Then `commands.DeleteDomain` is sent to the registry
And Domain returns normally without an error dialog
"""
- domain = create_ready_domain()
- # Put in client hold
- domain.place_client_hold()
- p = "userpass"
- self.client.login(username="staffuser", password=p)
-
- # Ensure everything is displaying correctly
- response = self.client.get(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- follow=True,
- )
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, domain.name)
- self.assertContains(response, "Remove from registry")
-
- # Test the info dialog
- request = self.factory.post(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- {"_delete_domain": "Remove from registry", "name": domain.name},
- follow=True,
- )
- request.user = self.client
-
- # Delete it once
- with patch("django.contrib.messages.add_message") as mock_add_message:
- self.admin.do_delete_domain(request, domain)
- mock_add_message.assert_called_once_with(
- request,
- messages.INFO,
- "Domain city.gov has been deleted. Thanks!",
- extra_tags="",
- fail_silently=False,
+ with less_console_noise():
+ domain = create_ready_domain()
+ # Put in client hold
+ domain.place_client_hold()
+ p = "userpass"
+ self.client.login(username="staffuser", password=p)
+ # Ensure everything is displaying correctly
+ response = self.client.get(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ follow=True,
)
-
- self.assertEqual(domain.state, Domain.State.DELETED)
-
- # Try to delete it again
- # Test the info dialog
- request = self.factory.post(
- "/admin/registrar/domain/{}/change/".format(domain.pk),
- {"_delete_domain": "Remove from registry", "name": domain.name},
- follow=True,
- )
- request.user = self.client
-
- with patch("django.contrib.messages.add_message") as mock_add_message:
- self.admin.do_delete_domain(request, domain)
- mock_add_message.assert_called_once_with(
- request,
- messages.INFO,
- "This domain is already deleted",
- extra_tags="",
- fail_silently=False,
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, domain.name)
+ self.assertContains(response, "Remove from registry")
+ # Test the info dialog
+ request = self.factory.post(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ {"_delete_domain": "Remove from registry", "name": domain.name},
+ follow=True,
)
+ request.user = self.client
+ # Delete it once
+ with patch("django.contrib.messages.add_message") as mock_add_message:
+ self.admin.do_delete_domain(request, domain)
+ mock_add_message.assert_called_once_with(
+ request,
+ messages.INFO,
+ "Domain city.gov has been deleted. Thanks!",
+ extra_tags="",
+ fail_silently=False,
+ )
- self.assertEqual(domain.state, Domain.State.DELETED)
+ self.assertEqual(domain.state, Domain.State.DELETED)
+ # Try to delete it again
+ # Test the info dialog
+ request = self.factory.post(
+ "/admin/registrar/domain/{}/change/".format(domain.pk),
+ {"_delete_domain": "Remove from registry", "name": domain.name},
+ follow=True,
+ )
+ request.user = self.client
+ with patch("django.contrib.messages.add_message") as mock_add_message:
+ self.admin.do_delete_domain(request, domain)
+ mock_add_message.assert_called_once_with(
+ request,
+ messages.INFO,
+ "This domain is already deleted",
+ extra_tags="",
+ fail_silently=False,
+ )
+ self.assertEqual(domain.state, Domain.State.DELETED)
@skip("Waiting on epp lib to implement")
def test_place_and_remove_hold_epp(self):
@@ -624,6 +614,7 @@ class TestDomainApplicationAdmin(MockEppLib):
"anything_else",
"is_policy_acknowledged",
"submission_date",
+ "notes",
"current_websites",
"other_contacts",
"alternative_domains",
@@ -641,6 +632,7 @@ class TestDomainApplicationAdmin(MockEppLib):
"creator",
"about_your_organization",
"requested_domain",
+ "approved_domain",
"alternative_domains",
"purpose",
"submitter",
@@ -1066,7 +1058,7 @@ class DomainInvitationAdminTest(TestCase):
self.assertContains(response, retrieved_html, count=1)
-class DomainInformationAdminTest(TestCase):
+class TestDomainInformationAdmin(TestCase):
def setUp(self):
"""Setup environment for a mock admin user"""
self.site = AdminSite()
@@ -1074,6 +1066,7 @@ class DomainInformationAdminTest(TestCase):
self.admin = DomainInformationAdmin(model=DomainInformation, admin_site=self.site)
self.client = Client(HTTP_HOST="localhost:8080")
self.superuser = create_superuser()
+ self.staffuser = create_user()
self.mock_data_generator = AuditedAdminMockData()
self.test_helper = GenericTestHelper(
@@ -1117,6 +1110,27 @@ class DomainInformationAdminTest(TestCase):
Contact.objects.all().delete()
User.objects.all().delete()
+ def test_readonly_fields_for_analyst(self):
+ """Ensures that analysts have their permissions setup correctly"""
+ request = self.factory.get("/")
+ request.user = self.staffuser
+
+ readonly_fields = self.admin.get_readonly_fields(request)
+
+ expected_fields = [
+ "creator",
+ "type_of_work",
+ "more_organization_information",
+ "domain",
+ "domain_application",
+ "submitter",
+ "no_other_contacts_rationale",
+ "anything_else",
+ "is_policy_acknowledged",
+ ]
+
+ self.assertEqual(readonly_fields, expected_fields)
+
def test_domain_sortable(self):
"""Tests if DomainInformation sorts by domain correctly"""
p = "adminpass"
@@ -1281,64 +1295,62 @@ class ListHeaderAdminTest(TestCase):
self.superuser = create_superuser()
def test_changelist_view(self):
- # Have to get creative to get past linter
- p = "adminpass"
- self.client.login(username="superuser", password=p)
-
- # Mock a user
- user = mock_user()
-
- # Make the request using the Client class
- # which handles CSRF
- # Follow=True handles the redirect
- response = self.client.get(
- "/admin/registrar/domainapplication/",
- {
- "status__exact": "started",
- "investigator__id__exact": user.id,
- "q": "Hello",
- },
- follow=True,
- )
-
- # Assert that the filters and search_query are added to the extra_context
- self.assertIn("filters", response.context)
- self.assertIn("search_query", response.context)
- # Assert the content of filters and search_query
- filters = response.context["filters"]
- search_query = response.context["search_query"]
- self.assertEqual(search_query, "Hello")
- self.assertEqual(
- filters,
- [
- {"parameter_name": "status", "parameter_value": "started"},
+ with less_console_noise():
+ # Have to get creative to get past linter
+ p = "adminpass"
+ self.client.login(username="superuser", password=p)
+ # Mock a user
+ user = mock_user()
+ # Make the request using the Client class
+ # which handles CSRF
+ # Follow=True handles the redirect
+ response = self.client.get(
+ "/admin/registrar/domainapplication/",
{
- "parameter_name": "investigator",
- "parameter_value": user.first_name + " " + user.last_name,
+ "status__exact": "started",
+ "investigator__id__exact": user.id,
+ "q": "Hello",
},
- ],
- )
+ follow=True,
+ )
+ # Assert that the filters and search_query are added to the extra_context
+ self.assertIn("filters", response.context)
+ self.assertIn("search_query", response.context)
+ # Assert the content of filters and search_query
+ filters = response.context["filters"]
+ search_query = response.context["search_query"]
+ self.assertEqual(search_query, "Hello")
+ self.assertEqual(
+ filters,
+ [
+ {"parameter_name": "status", "parameter_value": "started"},
+ {
+ "parameter_name": "investigator",
+ "parameter_value": user.first_name + " " + user.last_name,
+ },
+ ],
+ )
def test_get_filters(self):
- # Create a mock request object
- request = self.factory.get("/admin/yourmodel/")
- # Set the GET parameters for testing
- request.GET = {
- "status": "started",
- "investigator": "Jeff Lebowski",
- "q": "search_value",
- }
- # Call the get_filters method
- filters = self.admin.get_filters(request)
-
- # Assert the filters extracted from the request GET
- self.assertEqual(
- filters,
- [
- {"parameter_name": "status", "parameter_value": "started"},
- {"parameter_name": "investigator", "parameter_value": "Jeff Lebowski"},
- ],
- )
+ with less_console_noise():
+ # Create a mock request object
+ request = self.factory.get("/admin/yourmodel/")
+ # Set the GET parameters for testing
+ request.GET = {
+ "status": "started",
+ "investigator": "Jeff Lebowski",
+ "q": "search_value",
+ }
+ # Call the get_filters method
+ filters = self.admin.get_filters(request)
+ # Assert the filters extracted from the request GET
+ self.assertEqual(
+ filters,
+ [
+ {"parameter_name": "status", "parameter_value": "started"},
+ {"parameter_name": "investigator", "parameter_value": "Jeff Lebowski"},
+ ],
+ )
def tearDown(self):
# delete any applications too
@@ -1777,42 +1789,38 @@ class ContactAdminTest(TestCase):
def test_change_view_for_joined_contact_five_or_more(self):
"""Create a contact, join it to 5 domain requests. The 6th join will be a user.
Assert that the warning on the contact form lists 5 joins and a '1 more' ellispsis."""
-
- self.client.force_login(self.superuser)
-
- # Create an instance of the model
- # join it to 5 domain requests. The 6th join will be a user.
- contact, _ = Contact.objects.get_or_create(user=self.staffuser)
- application1 = completed_application(submitter=contact, name="city1.gov")
- application2 = completed_application(submitter=contact, name="city2.gov")
- application3 = completed_application(submitter=contact, name="city3.gov")
- application4 = completed_application(submitter=contact, name="city4.gov")
- application5 = completed_application(submitter=contact, name="city5.gov")
-
- with patch("django.contrib.messages.warning") as mock_warning:
- # Use the test client to simulate the request
- response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk]))
-
- logger.info(mock_warning)
-
- # Assert that the error message was called with the correct argument
- # Note: The 6th join will be a user.
- mock_warning.assert_called_once_with(
- response.wsgi_request,
- "
"
- "Joined to DomainApplication: city1.gov "
- "Joined to DomainApplication: city2.gov "
- "Joined to DomainApplication: city3.gov "
- "Joined to DomainApplication: city4.gov "
- "Joined to DomainApplication: city5.gov "
- " "
- "
And 1 more...
",
- )
+ with less_console_noise():
+ self.client.force_login(self.superuser)
+ # Create an instance of the model
+ # join it to 5 domain requests. The 6th join will be a user.
+ contact, _ = Contact.objects.get_or_create(user=self.staffuser)
+ application1 = completed_application(submitter=contact, name="city1.gov")
+ application2 = completed_application(submitter=contact, name="city2.gov")
+ application3 = completed_application(submitter=contact, name="city3.gov")
+ application4 = completed_application(submitter=contact, name="city4.gov")
+ application5 = completed_application(submitter=contact, name="city5.gov")
+ with patch("django.contrib.messages.warning") as mock_warning:
+ # Use the test client to simulate the request
+ response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk]))
+ logger.debug(mock_warning)
+ # Assert that the error message was called with the correct argument
+ # Note: The 6th join will be a user.
+ mock_warning.assert_called_once_with(
+ response.wsgi_request,
+ "
"
+ "Joined to DomainApplication: city1.gov "
+ "Joined to DomainApplication: city2.gov "
+ "Joined to DomainApplication: city3.gov "
+ "Joined to DomainApplication: city4.gov "
+ "Joined to DomainApplication: city5.gov "
+ " "
+ "
And 1 more...
",
+ )
def tearDown(self):
DomainApplication.objects.all().delete()
diff --git a/src/registrar/tests/test_management_scripts.py b/src/registrar/tests/test_management_scripts.py
index 06886ba66..34178e262 100644
--- a/src/registrar/tests/test_management_scripts.py
+++ b/src/registrar/tests/test_management_scripts.py
@@ -1,5 +1,6 @@
import copy
-import datetime
+from datetime import date, datetime, time
+from django.utils import timezone
from django.test import TestCase
@@ -17,7 +18,7 @@ from django.core.management import call_command
from unittest.mock import patch, call
from epplibwrapper import commands, common
-from .common import MockEppLib
+from .common import MockEppLib, less_console_noise
class TestPopulateFirstReady(TestCase):
@@ -33,7 +34,9 @@ class TestPopulateFirstReady(TestCase):
self.unknown_domain, _ = Domain.objects.get_or_create(name="fakeunknown.gov", state=Domain.State.UNKNOWN)
# Set a ready_at date for testing purposes
- self.ready_at_date = datetime.date(2022, 12, 31)
+ self.ready_at_date = date(2022, 12, 31)
+ _ready_at_datetime = datetime.combine(self.ready_at_date, time.min)
+ self.ready_at_date_tz_aware = timezone.make_aware(_ready_at_datetime, timezone=timezone.utc)
def tearDown(self):
"""Deletes all DB objects related to migrations"""
@@ -49,122 +52,103 @@ class TestPopulateFirstReady(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the populate_first_ready command with the specified arguments.
"""
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command("populate_first_ready")
+ with less_console_noise():
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command("populate_first_ready")
def test_populate_first_ready_state_ready(self):
"""
Tests that the populate_first_ready works as expected for the state 'ready'
"""
- # Set the created at date
- self.ready_domain.created_at = self.ready_at_date
- self.ready_domain.save()
-
- desired_domain = copy.deepcopy(self.ready_domain)
-
- desired_domain.first_ready = self.ready_at_date
-
- # Run the expiration date script
- self.run_populate_first_ready()
-
- self.assertEqual(desired_domain, self.ready_domain)
-
- # Explicitly test the first_ready date
- first_ready = Domain.objects.filter(name="fakeready.gov").get().first_ready
- self.assertEqual(first_ready, self.ready_at_date)
+ with less_console_noise():
+ # Set the created at date
+ self.ready_domain.created_at = self.ready_at_date_tz_aware
+ self.ready_domain.save()
+ desired_domain = copy.deepcopy(self.ready_domain)
+ desired_domain.first_ready = self.ready_at_date
+ # Run the expiration date script
+ self.run_populate_first_ready()
+ self.assertEqual(desired_domain, self.ready_domain)
+ # Explicitly test the first_ready date
+ first_ready = Domain.objects.filter(name="fakeready.gov").get().first_ready
+ self.assertEqual(first_ready, self.ready_at_date)
def test_populate_first_ready_state_deleted(self):
"""
Tests that the populate_first_ready works as expected for the state 'deleted'
"""
- # Set the created at date
- self.deleted_domain.created_at = self.ready_at_date
- self.deleted_domain.save()
-
- desired_domain = copy.deepcopy(self.deleted_domain)
-
- desired_domain.first_ready = self.ready_at_date
-
- # Run the expiration date script
- self.run_populate_first_ready()
-
- self.assertEqual(desired_domain, self.deleted_domain)
-
- # Explicitly test the first_ready date
- first_ready = Domain.objects.filter(name="fakedeleted.gov").get().first_ready
- self.assertEqual(first_ready, self.ready_at_date)
+ with less_console_noise():
+ # Set the created at date
+ self.deleted_domain.created_at = self.ready_at_date_tz_aware
+ self.deleted_domain.save()
+ desired_domain = copy.deepcopy(self.deleted_domain)
+ desired_domain.first_ready = self.ready_at_date
+ # Run the expiration date script
+ self.run_populate_first_ready()
+ self.assertEqual(desired_domain, self.deleted_domain)
+ # Explicitly test the first_ready date
+ first_ready = Domain.objects.filter(name="fakedeleted.gov").get().first_ready
+ self.assertEqual(first_ready, self.ready_at_date)
def test_populate_first_ready_state_dns_needed(self):
"""
Tests that the populate_first_ready doesn't make changes when a domain's state is 'dns_needed'
"""
- # Set the created at date
- self.dns_needed_domain.created_at = self.ready_at_date
- self.dns_needed_domain.save()
-
- desired_domain = copy.deepcopy(self.dns_needed_domain)
-
- desired_domain.first_ready = None
-
- # Run the expiration date script
- self.run_populate_first_ready()
-
- current_domain = self.dns_needed_domain
- # The object should largely be unaltered (does not test first_ready)
- self.assertEqual(desired_domain, current_domain)
-
- first_ready = Domain.objects.filter(name="fakedns.gov").get().first_ready
-
- # Explicitly test the first_ready date
- self.assertNotEqual(first_ready, self.ready_at_date)
- self.assertEqual(first_ready, None)
+ with less_console_noise():
+ # Set the created at date
+ self.dns_needed_domain.created_at = self.ready_at_date_tz_aware
+ self.dns_needed_domain.save()
+ desired_domain = copy.deepcopy(self.dns_needed_domain)
+ desired_domain.first_ready = None
+ # Run the expiration date script
+ self.run_populate_first_ready()
+ current_domain = self.dns_needed_domain
+ # The object should largely be unaltered (does not test first_ready)
+ self.assertEqual(desired_domain, current_domain)
+ first_ready = Domain.objects.filter(name="fakedns.gov").get().first_ready
+ # Explicitly test the first_ready date
+ self.assertNotEqual(first_ready, self.ready_at_date)
+ self.assertEqual(first_ready, None)
def test_populate_first_ready_state_on_hold(self):
"""
Tests that the populate_first_ready works as expected for the state 'on_hold'
"""
- self.hold_domain.created_at = self.ready_at_date
- self.hold_domain.save()
-
- desired_domain = copy.deepcopy(self.hold_domain)
- desired_domain.first_ready = self.ready_at_date
-
- # Run the update first ready_at script
- self.run_populate_first_ready()
-
- current_domain = self.hold_domain
- self.assertEqual(desired_domain, current_domain)
-
- # Explicitly test the first_ready date
- first_ready = Domain.objects.filter(name="fakehold.gov").get().first_ready
- self.assertEqual(first_ready, self.ready_at_date)
+ with less_console_noise():
+ self.hold_domain.created_at = self.ready_at_date_tz_aware
+ self.hold_domain.save()
+ desired_domain = copy.deepcopy(self.hold_domain)
+ desired_domain.first_ready = self.ready_at_date
+ # Run the update first ready_at script
+ self.run_populate_first_ready()
+ current_domain = self.hold_domain
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the first_ready date
+ first_ready = Domain.objects.filter(name="fakehold.gov").get().first_ready
+ self.assertEqual(first_ready, self.ready_at_date)
def test_populate_first_ready_state_unknown(self):
"""
Tests that the populate_first_ready works as expected for the state 'unknown'
"""
- # Set the created at date
- self.unknown_domain.created_at = self.ready_at_date
- self.unknown_domain.save()
-
- desired_domain = copy.deepcopy(self.unknown_domain)
- desired_domain.first_ready = None
-
- # Run the expiration date script
- self.run_populate_first_ready()
-
- current_domain = self.unknown_domain
-
- # The object should largely be unaltered (does not test first_ready)
- self.assertEqual(desired_domain, current_domain)
-
- # Explicitly test the first_ready date
- first_ready = Domain.objects.filter(name="fakeunknown.gov").get().first_ready
- self.assertNotEqual(first_ready, self.ready_at_date)
- self.assertEqual(first_ready, None)
+ with less_console_noise():
+ # Set the created at date
+ self.unknown_domain.created_at = self.ready_at_date_tz_aware
+ self.unknown_domain.save()
+ desired_domain = copy.deepcopy(self.unknown_domain)
+ desired_domain.first_ready = None
+ # Run the expiration date script
+ self.run_populate_first_ready()
+ current_domain = self.unknown_domain
+ # The object should largely be unaltered (does not test first_ready)
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the first_ready date
+ first_ready = Domain.objects.filter(name="fakeunknown.gov").get().first_ready
+ self.assertNotEqual(first_ready, self.ready_at_date)
+ self.assertEqual(first_ready, None)
class TestPatchAgencyInfo(TestCase):
@@ -185,7 +169,8 @@ class TestPatchAgencyInfo(TestCase):
@patch("registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", return_value=True)
def call_patch_federal_agency_info(self, mock_prompt):
"""Calls the patch_federal_agency_info command and mimics a keypress"""
- call_command("patch_federal_agency_info", "registrar/tests/data/fake_current_full.csv", debug=True)
+ with less_console_noise():
+ call_command("patch_federal_agency_info", "registrar/tests/data/fake_current_full.csv", debug=True)
def test_patch_agency_info(self):
"""
@@ -194,17 +179,14 @@ class TestPatchAgencyInfo(TestCase):
of a `DomainInformation` object when the corresponding
`TransitionDomain` object has a valid `federal_agency`.
"""
-
- # Ensure that the federal_agency is None
- self.assertEqual(self.domain_info.federal_agency, None)
-
- self.call_patch_federal_agency_info()
-
- # Reload the domain_info object from the database
- self.domain_info.refresh_from_db()
-
- # Check that the federal_agency field was updated
- self.assertEqual(self.domain_info.federal_agency, "test agency")
+ with less_console_noise():
+ # Ensure that the federal_agency is None
+ self.assertEqual(self.domain_info.federal_agency, None)
+ self.call_patch_federal_agency_info()
+ # Reload the domain_info object from the database
+ self.domain_info.refresh_from_db()
+ # Check that the federal_agency field was updated
+ self.assertEqual(self.domain_info.federal_agency, "test agency")
def test_patch_agency_info_skip(self):
"""
@@ -213,21 +195,18 @@ class TestPatchAgencyInfo(TestCase):
of a `DomainInformation` object when the corresponding
`TransitionDomain` object does not exist.
"""
- # Set federal_agency to None to simulate a skip
- self.transition_domain.federal_agency = None
- self.transition_domain.save()
-
- with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
- self.call_patch_federal_agency_info()
-
- # Check that the correct log message was output
- self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
-
- # Reload the domain_info object from the database
- self.domain_info.refresh_from_db()
-
- # Check that the federal_agency field was not updated
- self.assertIsNone(self.domain_info.federal_agency)
+ with less_console_noise():
+ # Set federal_agency to None to simulate a skip
+ self.transition_domain.federal_agency = None
+ self.transition_domain.save()
+ with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
+ self.call_patch_federal_agency_info()
+ # Check that the correct log message was output
+ self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
+ # Reload the domain_info object from the database
+ self.domain_info.refresh_from_db()
+ # Check that the federal_agency field was not updated
+ self.assertIsNone(self.domain_info.federal_agency)
def test_patch_agency_info_skip_updates_data(self):
"""
@@ -235,25 +214,21 @@ class TestPatchAgencyInfo(TestCase):
updates the DomainInformation object, because a record exists in the
provided current-full.csv file.
"""
- # Set federal_agency to None to simulate a skip
- self.transition_domain.federal_agency = None
- self.transition_domain.save()
-
- # Change the domain name to something parsable in the .csv
- self.domain.name = "cdomain1.gov"
- self.domain.save()
-
- with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
- self.call_patch_federal_agency_info()
-
- # Check that the correct log message was output
- self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
-
- # Reload the domain_info object from the database
- self.domain_info.refresh_from_db()
-
- # Check that the federal_agency field was not updated
- self.assertEqual(self.domain_info.federal_agency, "World War I Centennial Commission")
+ with less_console_noise():
+ # Set federal_agency to None to simulate a skip
+ self.transition_domain.federal_agency = None
+ self.transition_domain.save()
+ # Change the domain name to something parsable in the .csv
+ self.domain.name = "cdomain1.gov"
+ self.domain.save()
+ with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
+ self.call_patch_federal_agency_info()
+ # Check that the correct log message was output
+ self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
+ # Reload the domain_info object from the database
+ self.domain_info.refresh_from_db()
+ # Check that the federal_agency field was not updated
+ self.assertEqual(self.domain_info.federal_agency, "World War I Centennial Commission")
def test_patch_agency_info_skips_valid_domains(self):
"""
@@ -261,20 +236,17 @@ class TestPatchAgencyInfo(TestCase):
does not update the `federal_agency` field
of a `DomainInformation` object
"""
- self.domain_info.federal_agency = "unchanged"
- self.domain_info.save()
-
- with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="INFO") as context:
- self.call_patch_federal_agency_info()
-
- # Check that the correct log message was output
- self.assertIn("FINISHED", context.output[1])
-
- # Reload the domain_info object from the database
- self.domain_info.refresh_from_db()
-
- # Check that the federal_agency field was not updated
- self.assertEqual(self.domain_info.federal_agency, "unchanged")
+ with less_console_noise():
+ self.domain_info.federal_agency = "unchanged"
+ self.domain_info.save()
+ with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="INFO") as context:
+ self.call_patch_federal_agency_info()
+ # Check that the correct log message was output
+ self.assertIn("FINISHED", context.output[1])
+ # Reload the domain_info object from the database
+ self.domain_info.refresh_from_db()
+ # Check that the federal_agency field was not updated
+ self.assertEqual(self.domain_info.federal_agency, "unchanged")
class TestExtendExpirationDates(MockEppLib):
@@ -283,39 +255,37 @@ class TestExtendExpirationDates(MockEppLib):
super().setUp()
# Create a valid domain that is updatable
Domain.objects.get_or_create(
- name="waterbutpurple.gov", state=Domain.State.READY, expiration_date=datetime.date(2023, 11, 15)
+ name="waterbutpurple.gov", state=Domain.State.READY, expiration_date=date(2023, 11, 15)
)
TransitionDomain.objects.get_or_create(
username="testytester@mail.com",
domain_name="waterbutpurple.gov",
- epp_expiration_date=datetime.date(2023, 11, 15),
+ epp_expiration_date=date(2023, 11, 15),
)
# Create a domain with an invalid expiration date
- Domain.objects.get_or_create(
- name="fake.gov", state=Domain.State.READY, expiration_date=datetime.date(2022, 5, 25)
- )
+ Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY, expiration_date=date(2022, 5, 25))
TransitionDomain.objects.get_or_create(
username="themoonisactuallycheese@mail.com",
domain_name="fake.gov",
- epp_expiration_date=datetime.date(2022, 5, 25),
+ epp_expiration_date=date(2022, 5, 25),
)
# Create a domain with an invalid state
Domain.objects.get_or_create(
- name="fakeneeded.gov", state=Domain.State.DNS_NEEDED, expiration_date=datetime.date(2023, 11, 15)
+ name="fakeneeded.gov", state=Domain.State.DNS_NEEDED, expiration_date=date(2023, 11, 15)
)
TransitionDomain.objects.get_or_create(
username="fakeneeded@mail.com",
domain_name="fakeneeded.gov",
- epp_expiration_date=datetime.date(2023, 11, 15),
+ epp_expiration_date=date(2023, 11, 15),
)
# Create a domain with a date greater than the maximum
Domain.objects.get_or_create(
- name="fakemaximum.gov", state=Domain.State.READY, expiration_date=datetime.date(2024, 12, 31)
+ name="fakemaximum.gov", state=Domain.State.READY, expiration_date=date(2024, 12, 31)
)
TransitionDomain.objects.get_or_create(
username="fakemaximum@mail.com",
domain_name="fakemaximum.gov",
- epp_expiration_date=datetime.date(2024, 12, 31),
+ epp_expiration_date=date(2024, 12, 31),
)
def tearDown(self):
@@ -338,83 +308,82 @@ class TestExtendExpirationDates(MockEppLib):
The 'call_command' function from Django's management framework is then used to
execute the extend_expiration_dates command with the specified arguments.
"""
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command("extend_expiration_dates")
+ with less_console_noise():
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command("extend_expiration_dates")
def test_extends_expiration_date_correctly(self):
"""
Tests that the extend_expiration_dates method extends dates as expected
"""
- desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
- desired_domain.expiration_date = datetime.date(2024, 11, 15)
-
- # Run the expiration date script
- self.run_extend_expiration_dates()
-
- current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
-
- self.assertEqual(desired_domain, current_domain)
- # Explicitly test the expiration date
- self.assertEqual(current_domain.expiration_date, datetime.date(2024, 11, 15))
+ with less_console_noise():
+ desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
+ desired_domain.expiration_date = date(2024, 11, 15)
+ # Run the expiration date script
+ self.run_extend_expiration_dates()
+ current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the expiration date
+ self.assertEqual(current_domain.expiration_date, date(2024, 11, 15))
def test_extends_expiration_date_skips_non_current(self):
"""
Tests that the extend_expiration_dates method correctly skips domains
with an expiration date less than a certain threshold.
"""
- desired_domain = Domain.objects.filter(name="fake.gov").get()
- desired_domain.expiration_date = datetime.date(2022, 5, 25)
-
- # Run the expiration date script
- self.run_extend_expiration_dates()
-
- current_domain = Domain.objects.filter(name="fake.gov").get()
- self.assertEqual(desired_domain, current_domain)
-
- # Explicitly test the expiration date. The extend_expiration_dates script
- # will skip all dates less than date(2023, 11, 15), meaning that this domain
- # should not be affected by the change.
- self.assertEqual(current_domain.expiration_date, datetime.date(2022, 5, 25))
+ with less_console_noise():
+ desired_domain = Domain.objects.filter(name="fake.gov").get()
+ desired_domain.expiration_date = date(2022, 5, 25)
+ # Run the expiration date script
+ self.run_extend_expiration_dates()
+ current_domain = Domain.objects.filter(name="fake.gov").get()
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the expiration date. The extend_expiration_dates script
+ # will skip all dates less than date(2023, 11, 15), meaning that this domain
+ # should not be affected by the change.
+ self.assertEqual(current_domain.expiration_date, date(2022, 5, 25))
def test_extends_expiration_date_skips_maximum_date(self):
"""
Tests that the extend_expiration_dates method correctly skips domains
with an expiration date more than a certain threshold.
"""
- desired_domain = Domain.objects.filter(name="fakemaximum.gov").get()
- desired_domain.expiration_date = datetime.date(2024, 12, 31)
+ with less_console_noise():
+ desired_domain = Domain.objects.filter(name="fakemaximum.gov").get()
+ desired_domain.expiration_date = date(2024, 12, 31)
- # Run the expiration date script
- self.run_extend_expiration_dates()
+ # Run the expiration date script
+ self.run_extend_expiration_dates()
- current_domain = Domain.objects.filter(name="fakemaximum.gov").get()
- self.assertEqual(desired_domain, current_domain)
+ current_domain = Domain.objects.filter(name="fakemaximum.gov").get()
+ self.assertEqual(desired_domain, current_domain)
- # Explicitly test the expiration date. The extend_expiration_dates script
- # will skip all dates less than date(2023, 11, 15), meaning that this domain
- # should not be affected by the change.
- self.assertEqual(current_domain.expiration_date, datetime.date(2024, 12, 31))
+ # Explicitly test the expiration date. The extend_expiration_dates script
+ # will skip all dates less than date(2023, 11, 15), meaning that this domain
+ # should not be affected by the change.
+ self.assertEqual(current_domain.expiration_date, date(2024, 12, 31))
def test_extends_expiration_date_skips_non_ready(self):
"""
Tests that the extend_expiration_dates method correctly skips domains not in the state "ready"
"""
- desired_domain = Domain.objects.filter(name="fakeneeded.gov").get()
- desired_domain.expiration_date = datetime.date(2023, 11, 15)
+ with less_console_noise():
+ desired_domain = Domain.objects.filter(name="fakeneeded.gov").get()
+ desired_domain.expiration_date = date(2023, 11, 15)
- # Run the expiration date script
- self.run_extend_expiration_dates()
+ # Run the expiration date script
+ self.run_extend_expiration_dates()
- current_domain = Domain.objects.filter(name="fakeneeded.gov").get()
- self.assertEqual(desired_domain, current_domain)
+ current_domain = Domain.objects.filter(name="fakeneeded.gov").get()
+ self.assertEqual(desired_domain, current_domain)
- # Explicitly test the expiration date. The extend_expiration_dates script
- # will skip all dates less than date(2023, 11, 15), meaning that this domain
- # should not be affected by the change.
- self.assertEqual(current_domain.expiration_date, datetime.date(2023, 11, 15))
+ # Explicitly test the expiration date. The extend_expiration_dates script
+ # will skip all dates less than date(2023, 11, 15), meaning that this domain
+ # should not be affected by the change.
+ self.assertEqual(current_domain.expiration_date, date(2023, 11, 15))
def test_extends_expiration_date_idempotent(self):
"""
@@ -423,26 +392,21 @@ class TestExtendExpirationDates(MockEppLib):
Verifies that running the method multiple times does not change the expiration date
of a domain beyond the initial extension.
"""
- desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
- desired_domain.expiration_date = datetime.date(2024, 11, 15)
-
- # Run the expiration date script
- self.run_extend_expiration_dates()
-
- current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
- self.assertEqual(desired_domain, current_domain)
-
- # Explicitly test the expiration date
- self.assertEqual(desired_domain.expiration_date, datetime.date(2024, 11, 15))
-
- # Run the expiration date script again
- self.run_extend_expiration_dates()
-
- # The old domain shouldn't have changed
- self.assertEqual(desired_domain, current_domain)
-
- # Explicitly test the expiration date - should be the same
- self.assertEqual(desired_domain.expiration_date, datetime.date(2024, 11, 15))
+ with less_console_noise():
+ desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
+ desired_domain.expiration_date = date(2024, 11, 15)
+ # Run the expiration date script
+ self.run_extend_expiration_dates()
+ current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the expiration date
+ self.assertEqual(desired_domain.expiration_date, date(2024, 11, 15))
+ # Run the expiration date script again
+ self.run_extend_expiration_dates()
+ # The old domain shouldn't have changed
+ self.assertEqual(desired_domain, current_domain)
+ # Explicitly test the expiration date - should be the same
+ self.assertEqual(desired_domain.expiration_date, date(2024, 11, 15))
class TestDiscloseEmails(MockEppLib):
@@ -461,39 +425,41 @@ class TestDiscloseEmails(MockEppLib):
The 'call_command' function from Django's management framework is then used to
execute the disclose_security_emails command.
"""
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command("disclose_security_emails")
+ with less_console_noise():
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command("disclose_security_emails")
def test_disclose_security_emails(self):
"""
Tests that command disclose_security_emails runs successfully with
appropriate EPP calll to UpdateContact.
"""
- domain, _ = Domain.objects.get_or_create(name="testdisclose.gov", state=Domain.State.READY)
- expectedSecContact = PublicContact.get_default_security()
- expectedSecContact.domain = domain
- expectedSecContact.email = "123@mail.gov"
- # set domain security email to 123@mail.gov instead of default email
- domain.security_contact = expectedSecContact
- self.run_disclose_security_emails()
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="testdisclose.gov", state=Domain.State.READY)
+ expectedSecContact = PublicContact.get_default_security()
+ expectedSecContact.domain = domain
+ expectedSecContact.email = "123@mail.gov"
+ # set domain security email to 123@mail.gov instead of default email
+ domain.security_contact = expectedSecContact
+ self.run_disclose_security_emails()
- # running disclose_security_emails sends EPP call UpdateContact with disclose
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.UpdateContact(
- id=domain.security_contact.registry_id,
- postal_info=domain._make_epp_contact_postal_info(contact=domain.security_contact),
- email=domain.security_contact.email,
- voice=domain.security_contact.voice,
- fax=domain.security_contact.fax,
- auth_info=common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
- disclose=domain._disclose_fields(contact=domain.security_contact),
- ),
- cleaned=True,
- )
- ]
- )
+ # running disclose_security_emails sends EPP call UpdateContact with disclose
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.UpdateContact(
+ id=domain.security_contact.registry_id,
+ postal_info=domain._make_epp_contact_postal_info(contact=domain.security_contact),
+ email=domain.security_contact.email,
+ voice=domain.security_contact.voice,
+ fax=domain.security_contact.fax,
+ auth_info=common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
+ disclose=domain._disclose_fields(contact=domain.security_contact),
+ ),
+ cleaned=True,
+ )
+ ]
+ )
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index d0005cbd5..294ec70af 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -60,127 +60,134 @@ class TestDomainApplication(TestCase):
def assertNotRaises(self, exception_type):
"""Helper method for testing allowed transitions."""
- return self.assertRaises(Exception, None, exception_type)
+ with less_console_noise():
+ return self.assertRaises(Exception, None, exception_type)
def test_empty_create_fails(self):
"""Can't create a completely empty domain application.
NOTE: something about theexception this test raises messes up with the
atomic block in a custom tearDown method for the parent test class."""
- with self.assertRaisesRegex(IntegrityError, "creator"):
- DomainApplication.objects.create()
+ with less_console_noise():
+ with self.assertRaisesRegex(IntegrityError, "creator"):
+ DomainApplication.objects.create()
def test_minimal_create(self):
"""Can create with just a creator."""
- user, _ = User.objects.get_or_create(username="testy")
- application = DomainApplication.objects.create(creator=user)
- self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED)
+ with less_console_noise():
+ user, _ = User.objects.get_or_create(username="testy")
+ application = DomainApplication.objects.create(creator=user)
+ self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED)
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")
- application = DomainApplication.objects.create(
- creator=user,
- investigator=user,
- organization_type=DomainApplication.OrganizationChoices.FEDERAL,
- federal_type=DomainApplication.BranchChoices.EXECUTIVE,
- is_election_board=False,
- organization_name="Test",
- address_line1="100 Main St.",
- address_line2="APT 1A",
- state_territory="CA",
- zipcode="12345-6789",
- authorizing_official=contact,
- requested_domain=domain,
- submitter=contact,
- purpose="Igorville rules!",
- anything_else="All of Igorville loves the dotgov program.",
- is_policy_acknowledged=True,
- )
- application.current_websites.add(com_website)
- application.alternative_domains.add(gov_website)
- application.other_contacts.add(contact)
- application.save()
+ with less_console_noise():
+ 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")
+ application = DomainApplication.objects.create(
+ creator=user,
+ investigator=user,
+ organization_type=DomainApplication.OrganizationChoices.FEDERAL,
+ federal_type=DomainApplication.BranchChoices.EXECUTIVE,
+ is_election_board=False,
+ organization_name="Test",
+ address_line1="100 Main St.",
+ address_line2="APT 1A",
+ state_territory="CA",
+ zipcode="12345-6789",
+ authorizing_official=contact,
+ requested_domain=domain,
+ submitter=contact,
+ purpose="Igorville rules!",
+ anything_else="All of Igorville loves the dotgov program.",
+ is_policy_acknowledged=True,
+ )
+ application.current_websites.add(com_website)
+ application.alternative_domains.add(gov_website)
+ application.other_contacts.add(contact)
+ application.save()
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,
- organization_type=DomainInformation.OrganizationChoices.FEDERAL,
- federal_type=DomainInformation.BranchChoices.EXECUTIVE,
- is_election_board=False,
- organization_name="Test",
- address_line1="100 Main St.",
- address_line2="APT 1A",
- state_territory="CA",
- zipcode="12345-6789",
- authorizing_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)
+ with less_console_noise():
+ 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,
+ organization_type=DomainInformation.OrganizationChoices.FEDERAL,
+ federal_type=DomainInformation.BranchChoices.EXECUTIVE,
+ is_election_board=False,
+ organization_name="Test",
+ address_line1="100 Main St.",
+ address_line2="APT 1A",
+ state_territory="CA",
+ zipcode="12345-6789",
+ authorizing_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)
def test_status_fsm_submit_fail(self):
- user, _ = User.objects.get_or_create(username="testy")
- application = DomainApplication.objects.create(creator=user)
+ with less_console_noise():
+ user, _ = User.objects.get_or_create(username="testy")
+ application = DomainApplication.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 an application with a null domain name
- application.submit()
+ with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
+ with less_console_noise():
+ with self.assertRaises(ValueError):
+ # can't submit an application with a null domain name
+ application.submit()
def test_status_fsm_submit_succeed(self):
- user, _ = User.objects.get_or_create(username="testy")
- site = DraftDomain.objects.create(name="igorville.gov")
- application = DomainApplication.objects.create(creator=user, requested_domain=site)
+ with less_console_noise():
+ user, _ = User.objects.get_or_create(username="testy")
+ site = DraftDomain.objects.create(name="igorville.gov")
+ application = DomainApplication.objects.create(creator=user, requested_domain=site)
- # no submitter email so this emits a log warning
+ # no submitter email so this emits a log warning
- with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
- with less_console_noise():
- application.submit()
- self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED)
+ with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
+ with less_console_noise():
+ application.submit()
+ self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED)
def test_submit_sends_email(self):
"""Create an application and submit it and see if email was sent."""
- user, _ = User.objects.get_or_create(username="testy")
- contact = Contact.objects.create(email="test@test.gov")
- domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
- application = DomainApplication.objects.create(
- creator=user,
- requested_domain=domain,
- submitter=contact,
- )
- application.save()
+ with less_console_noise():
+ user, _ = User.objects.get_or_create(username="testy")
+ contact = Contact.objects.create(email="test@test.gov")
+ domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
+ application = DomainApplication.objects.create(
+ creator=user,
+ requested_domain=domain,
+ submitter=contact,
+ )
+ application.save()
- with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
- with less_console_noise():
+ with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
application.submit()
- # check to see if an email was sent
- self.assertGreater(
- len(
- [
- email
- for email in MockSESClient.EMAILS_SENT
- if "test@test.gov" in email["kwargs"]["Destination"]["ToAddresses"]
- ]
- ),
- 0,
- )
+ # check to see if an email was sent
+ self.assertGreater(
+ len(
+ [
+ email
+ for email in MockSESClient.EMAILS_SENT
+ if "test@test.gov" in email["kwargs"]["Destination"]["ToAddresses"]
+ ]
+ ),
+ 0,
+ )
def test_submit_transition_allowed(self):
"""
@@ -268,13 +275,13 @@ class TestDomainApplication(TestCase):
(self.rejected_application, TransitionNotAllowed),
(self.ineligible_application, TransitionNotAllowed),
]
-
- for application, exception_type in test_cases:
- with self.subTest(application=application, exception_type=exception_type):
- try:
- application.action_needed()
- except TransitionNotAllowed:
- self.fail("TransitionNotAllowed was raised, but it was not expected.")
+ with less_console_noise():
+ for application, exception_type in test_cases:
+ with self.subTest(application=application, exception_type=exception_type):
+ try:
+ application.action_needed()
+ except TransitionNotAllowed:
+ self.fail("TransitionNotAllowed was raised, but it was not expected.")
def test_action_needed_transition_not_allowed(self):
"""
@@ -286,11 +293,11 @@ class TestDomainApplication(TestCase):
(self.action_needed_application, TransitionNotAllowed),
(self.withdrawn_application, TransitionNotAllowed),
]
-
- for application, exception_type in test_cases:
- with self.subTest(application=application, exception_type=exception_type):
- with self.assertRaises(exception_type):
- application.action_needed()
+ with less_console_noise():
+ for application, exception_type in test_cases:
+ with self.subTest(application=application, exception_type=exception_type):
+ with self.assertRaises(exception_type):
+ application.action_needed()
def test_approved_transition_allowed(self):
"""
@@ -499,25 +506,29 @@ class TestDomainApplication(TestCase):
def test_has_rationale_returns_true(self):
"""has_rationale() returns true when an application has no_other_contacts_rationale"""
- self.started_application.no_other_contacts_rationale = "You talkin' to me?"
- self.started_application.save()
- self.assertEquals(self.started_application.has_rationale(), True)
+ with less_console_noise():
+ self.started_application.no_other_contacts_rationale = "You talkin' to me?"
+ self.started_application.save()
+ self.assertEquals(self.started_application.has_rationale(), True)
def test_has_rationale_returns_false(self):
"""has_rationale() returns false when an application has no no_other_contacts_rationale"""
- self.assertEquals(self.started_application.has_rationale(), False)
+ with less_console_noise():
+ self.assertEquals(self.started_application.has_rationale(), False)
def test_has_other_contacts_returns_true(self):
"""has_other_contacts() returns true when an application has other_contacts"""
- # completed_application has other contacts by default
- self.assertEquals(self.started_application.has_other_contacts(), True)
+ with less_console_noise():
+ # completed_application has other contacts by default
+ self.assertEquals(self.started_application.has_other_contacts(), True)
def test_has_other_contacts_returns_false(self):
"""has_other_contacts() returns false when an application has no other_contacts"""
- application = completed_application(
- status=DomainApplication.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False
- )
- self.assertEquals(application.has_other_contacts(), False)
+ with less_console_noise():
+ application = completed_application(
+ status=DomainApplication.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False
+ )
+ self.assertEquals(application.has_other_contacts(), False)
class TestPermissions(TestCase):
@@ -548,9 +559,9 @@ class TestPermissions(TestCase):
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
-class TestDomainInfo(TestCase):
+class TestDomainInformation(TestCase):
- """Test creation of Domain Information when approved."""
+ """Test the DomainInformation model, when approved or otherwise"""
def setUp(self):
super().setUp()
@@ -559,12 +570,18 @@ class TestDomainInfo(TestCase):
def tearDown(self):
super().tearDown()
self.mock_client.EMAILS_SENT.clear()
+ Domain.objects.all().delete()
+ DomainInformation.objects.all().delete()
+ DomainApplication.objects.all().delete()
+ User.objects.all().delete()
+ DraftDomain.objects.all().delete()
@boto3_mocking.patching
def test_approval_creates_info(self):
+ self.maxDiff = None
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
user, _ = User.objects.get_or_create()
- application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain)
+ application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain, notes="test notes")
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
with less_console_noise():
@@ -574,7 +591,25 @@ class TestDomainInfo(TestCase):
# should be an information present for this domain
domain = Domain.objects.get(name="igorville.gov")
- self.assertTrue(DomainInformation.objects.get(domain=domain))
+ 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_application=application,
+ ).__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 TestInvitations(TestCase):
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index 9026832cd..ca0a5e8d8 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -7,6 +7,7 @@ from django.test import TestCase
from django.db.utils import IntegrityError
from unittest.mock import MagicMock, patch, call
import datetime
+from django.utils.timezone import make_aware
from registrar.models import Domain, Host, HostIP
from unittest import skip
@@ -46,158 +47,162 @@ class TestDomainCache(MockEppLib):
def test_cache_sets_resets(self):
"""Cache should be set on getter and reset on setter calls"""
- domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- # trigger getter
- _ = domain.creation_date
- domain._get_property("contacts")
- # getter should set the domain cache with a InfoDomain object
- # (see InfoDomainResult)
- self.assertEquals(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
- self.assertEquals(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
- status_list = [status.state for status in self.mockDataInfoDomain.statuses]
- self.assertEquals(domain._cache["statuses"], status_list)
- self.assertFalse("avail" in domain._cache.keys())
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ # trigger getter
+ _ = domain.creation_date
+ domain._get_property("contacts")
+ # getter should set the domain cache with a InfoDomain object
+ # (see InfoDomainResult)
+ self.assertEquals(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
+ self.assertEquals(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
+ status_list = [status.state for status in self.mockDataInfoDomain.statuses]
+ self.assertEquals(domain._cache["statuses"], status_list)
+ self.assertFalse("avail" in domain._cache.keys())
- # using a setter should clear the cache
- domain.dnssecdata = []
- self.assertEquals(domain._cache, {})
+ # using a setter should clear the cache
+ domain.dnssecdata = []
+ self.assertEquals(domain._cache, {})
- # send should have been called only once
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoDomain(name="igorville.gov", auth_info=None),
- cleaned=True,
- ),
- ],
- any_order=False, # Ensure calls are in the specified order
- )
+ # send should have been called only once
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(name="igorville.gov", auth_info=None),
+ cleaned=True,
+ ),
+ ],
+ any_order=False, # Ensure calls are in the specified order
+ )
def test_cache_used_when_avail(self):
"""Cache is pulled from if the object has already been accessed"""
- domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- cr_date = domain.creation_date
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ cr_date = domain.creation_date
- # repeat the getter call
- cr_date = domain.creation_date
+ # repeat the getter call
+ cr_date = domain.creation_date
- # value should still be set correctly
- self.assertEqual(cr_date, self.mockDataInfoDomain.cr_date)
- self.assertEqual(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
+ # value should still be set correctly
+ self.assertEqual(cr_date, self.mockDataInfoDomain.cr_date)
+ self.assertEqual(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
- # send was only called once & not on the second getter call
- expectedCalls = [
- call(commands.InfoDomain(name="igorville.gov", auth_info=None), cleaned=True),
- ]
+ # send was only called once & not on the second getter call
+ expectedCalls = [
+ call(commands.InfoDomain(name="igorville.gov", auth_info=None), cleaned=True),
+ ]
- self.mockedSendFunction.assert_has_calls(expectedCalls)
+ self.mockedSendFunction.assert_has_calls(expectedCalls)
def test_cache_nested_elements(self):
"""Cache works correctly with the nested objects cache and hosts"""
- domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- # The contact list will initially contain objects of type 'DomainContact'
- # this is then transformed into PublicContact, and cache should NOT
- # hold onto the DomainContact object
- expectedUnfurledContactsList = [
- common.DomainContact(contact="123", type="security"),
- ]
- expectedContactsDict = {
- PublicContact.ContactTypeChoices.ADMINISTRATIVE: None,
- PublicContact.ContactTypeChoices.SECURITY: "123",
- PublicContact.ContactTypeChoices.TECHNICAL: None,
- }
- expectedHostsDict = {
- "name": self.mockDataInfoDomain.hosts[0],
- "addrs": [item.addr for item in self.mockDataInfoHosts.addrs],
- "cr_date": self.mockDataInfoHosts.cr_date,
- }
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ # The contact list will initially contain objects of type 'DomainContact'
+ # this is then transformed into PublicContact, and cache should NOT
+ # hold onto the DomainContact object
+ expectedUnfurledContactsList = [
+ common.DomainContact(contact="123", type="security"),
+ ]
+ expectedContactsDict = {
+ PublicContact.ContactTypeChoices.ADMINISTRATIVE: None,
+ PublicContact.ContactTypeChoices.SECURITY: "123",
+ PublicContact.ContactTypeChoices.TECHNICAL: None,
+ }
+ expectedHostsDict = {
+ "name": self.mockDataInfoDomain.hosts[0],
+ "addrs": [item.addr for item in self.mockDataInfoHosts.addrs],
+ "cr_date": self.mockDataInfoHosts.cr_date,
+ }
- # this can be changed when the getter for contacts is implemented
- domain._get_property("contacts")
+ # this can be changed when the getter for contacts is implemented
+ domain._get_property("contacts")
- # check domain info is still correct and not overridden
- self.assertEqual(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
- self.assertEqual(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
+ # check domain info is still correct and not overridden
+ self.assertEqual(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
+ self.assertEqual(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
- # check contacts
- self.assertEqual(domain._cache["_contacts"], self.mockDataInfoDomain.contacts)
- # The contact list should not contain what is sent by the registry by default,
- # as _fetch_cache will transform the type to PublicContact
- self.assertNotEqual(domain._cache["contacts"], expectedUnfurledContactsList)
- self.assertEqual(domain._cache["contacts"], expectedContactsDict)
+ # check contacts
+ self.assertEqual(domain._cache["_contacts"], self.mockDataInfoDomain.contacts)
+ # The contact list should not contain what is sent by the registry by default,
+ # as _fetch_cache will transform the type to PublicContact
+ self.assertNotEqual(domain._cache["contacts"], expectedUnfurledContactsList)
+ self.assertEqual(domain._cache["contacts"], expectedContactsDict)
- # get and check hosts is set correctly
- domain._get_property("hosts")
- self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
- self.assertEqual(domain._cache["contacts"], expectedContactsDict)
- # invalidate cache
- domain._cache = {}
+ # get and check hosts is set correctly
+ domain._get_property("hosts")
+ self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
+ self.assertEqual(domain._cache["contacts"], expectedContactsDict)
+ # invalidate cache
+ domain._cache = {}
- # get host
- domain._get_property("hosts")
- self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
+ # get host
+ domain._get_property("hosts")
+ self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
- # get contacts
- domain._get_property("contacts")
- self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
- self.assertEqual(domain._cache["contacts"], expectedContactsDict)
+ # get contacts
+ domain._get_property("contacts")
+ self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
+ self.assertEqual(domain._cache["contacts"], expectedContactsDict)
def test_map_epp_contact_to_public_contact(self):
# Tests that the mapper is working how we expect
- domain, _ = Domain.objects.get_or_create(name="registry.gov")
- security = PublicContact.ContactTypeChoices.SECURITY
- mapped = domain.map_epp_contact_to_public_contact(
- self.mockDataInfoContact,
- self.mockDataInfoContact.id,
- security,
- )
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="registry.gov")
+ security = PublicContact.ContactTypeChoices.SECURITY
+ mapped = domain.map_epp_contact_to_public_contact(
+ self.mockDataInfoContact,
+ self.mockDataInfoContact.id,
+ security,
+ )
- expected_contact = PublicContact(
- domain=domain,
- contact_type=security,
- registry_id="123",
- email="123@mail.gov",
- voice="+1.8882820870",
- fax="+1-212-9876543",
- pw="lastPw",
- name="Registry Customer Service",
- org="Cybersecurity and Infrastructure Security Agency",
- city="Arlington",
- pc="22201",
- cc="US",
- sp="VA",
- street1="4200 Wilson Blvd.",
- )
+ expected_contact = PublicContact(
+ domain=domain,
+ contact_type=security,
+ registry_id="123",
+ email="123@mail.gov",
+ voice="+1.8882820870",
+ fax="+1-212-9876543",
+ pw="lastPw",
+ name="Registry Customer Service",
+ org="Cybersecurity and Infrastructure Security Agency",
+ city="Arlington",
+ pc="22201",
+ cc="US",
+ sp="VA",
+ street1="4200 Wilson Blvd.",
+ )
- # Test purposes only, since we're comparing
- # two duplicate objects. We would expect
- # these not to have the same state.
- expected_contact._state = mapped._state
+ # Test purposes only, since we're comparing
+ # two duplicate objects. We would expect
+ # these not to have the same state.
+ expected_contact._state = mapped._state
- # Mapped object is what we expect
- self.assertEqual(mapped.__dict__, expected_contact.__dict__)
+ # Mapped object is what we expect
+ self.assertEqual(mapped.__dict__, expected_contact.__dict__)
- # The mapped object should correctly translate to a DB
- # object. If not, something else went wrong.
- db_object = domain._get_or_create_public_contact(mapped)
- in_db = PublicContact.objects.filter(
- registry_id=domain.security_contact.registry_id,
- contact_type=security,
- ).get()
- # DB Object is the same as the mapped object
- self.assertEqual(db_object, in_db)
+ # The mapped object should correctly translate to a DB
+ # object. If not, something else went wrong.
+ db_object = domain._get_or_create_public_contact(mapped)
+ in_db = PublicContact.objects.filter(
+ registry_id=domain.security_contact.registry_id,
+ contact_type=security,
+ ).get()
+ # DB Object is the same as the mapped object
+ self.assertEqual(db_object, in_db)
- domain.security_contact = in_db
- # Trigger the getter
- _ = domain.security_contact
- # Check to see that changes made
- # to DB objects persist in cache correctly
- in_db.email = "123test@mail.gov"
- in_db.save()
+ domain.security_contact = in_db
+ # Trigger the getter
+ _ = domain.security_contact
+ # Check to see that changes made
+ # to DB objects persist in cache correctly
+ in_db.email = "123test@mail.gov"
+ in_db.save()
- cached_contact = domain._cache["contacts"].get(security)
- self.assertEqual(cached_contact, in_db.registry_id)
- self.assertEqual(domain.security_contact.email, "123test@mail.gov")
+ cached_contact = domain._cache["contacts"].get(security)
+ self.assertEqual(cached_contact, in_db.registry_id)
+ self.assertEqual(domain.security_contact.email, "123test@mail.gov")
def test_errors_map_epp_contact_to_public_contact(self):
"""
@@ -206,48 +211,49 @@ class TestDomainCache(MockEppLib):
gets invalid data from EPPLib
Then the function throws the expected ContactErrors
"""
- domain, _ = Domain.objects.get_or_create(name="registry.gov")
- fakedEpp = self.fakedEppObject()
- invalid_length = fakedEpp.dummyInfoContactResultData(
- "Cymaticsisasubsetofmodalvibrationalphenomena", "lengthInvalid@mail.gov"
- )
- valid_object = fakedEpp.dummyInfoContactResultData("valid", "valid@mail.gov")
-
- desired_error = ContactErrorCodes.CONTACT_ID_INVALID_LENGTH
- with self.assertRaises(ContactError) as context:
- domain.map_epp_contact_to_public_contact(
- invalid_length,
- invalid_length.id,
- PublicContact.ContactTypeChoices.SECURITY,
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="registry.gov")
+ fakedEpp = self.fakedEppObject()
+ invalid_length = fakedEpp.dummyInfoContactResultData(
+ "Cymaticsisasubsetofmodalvibrationalphenomena", "lengthInvalid@mail.gov"
)
- self.assertEqual(context.exception.code, desired_error)
+ valid_object = fakedEpp.dummyInfoContactResultData("valid", "valid@mail.gov")
- desired_error = ContactErrorCodes.CONTACT_ID_NONE
- with self.assertRaises(ContactError) as context:
- domain.map_epp_contact_to_public_contact(
- valid_object,
- None,
- PublicContact.ContactTypeChoices.SECURITY,
- )
- self.assertEqual(context.exception.code, desired_error)
+ desired_error = ContactErrorCodes.CONTACT_ID_INVALID_LENGTH
+ with self.assertRaises(ContactError) as context:
+ domain.map_epp_contact_to_public_contact(
+ invalid_length,
+ invalid_length.id,
+ PublicContact.ContactTypeChoices.SECURITY,
+ )
+ self.assertEqual(context.exception.code, desired_error)
- desired_error = ContactErrorCodes.CONTACT_INVALID_TYPE
- with self.assertRaises(ContactError) as context:
- domain.map_epp_contact_to_public_contact(
- "bad_object",
- valid_object.id,
- PublicContact.ContactTypeChoices.SECURITY,
- )
- self.assertEqual(context.exception.code, desired_error)
+ desired_error = ContactErrorCodes.CONTACT_ID_NONE
+ with self.assertRaises(ContactError) as context:
+ domain.map_epp_contact_to_public_contact(
+ valid_object,
+ None,
+ PublicContact.ContactTypeChoices.SECURITY,
+ )
+ self.assertEqual(context.exception.code, desired_error)
- desired_error = ContactErrorCodes.CONTACT_TYPE_NONE
- with self.assertRaises(ContactError) as context:
- domain.map_epp_contact_to_public_contact(
- valid_object,
- valid_object.id,
- None,
- )
- self.assertEqual(context.exception.code, desired_error)
+ desired_error = ContactErrorCodes.CONTACT_INVALID_TYPE
+ with self.assertRaises(ContactError) as context:
+ domain.map_epp_contact_to_public_contact(
+ "bad_object",
+ valid_object.id,
+ PublicContact.ContactTypeChoices.SECURITY,
+ )
+ self.assertEqual(context.exception.code, desired_error)
+
+ desired_error = ContactErrorCodes.CONTACT_TYPE_NONE
+ with self.assertRaises(ContactError) as context:
+ domain.map_epp_contact_to_public_contact(
+ valid_object,
+ valid_object.id,
+ None,
+ )
+ self.assertEqual(context.exception.code, desired_error)
class TestDomainCreation(MockEppLib):
@@ -346,42 +352,44 @@ class TestDomainStatuses(MockEppLib):
def test_get_status(self):
"""Domain 'statuses' getter returns statuses by calling epp"""
- domain, _ = Domain.objects.get_or_create(name="chicken-liver.gov")
- # trigger getter
- _ = domain.statuses
- status_list = [status.state for status in self.mockDataInfoDomain.statuses]
- self.assertEquals(domain._cache["statuses"], status_list)
- # Called in _fetch_cache
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoDomain(name="chicken-liver.gov", auth_info=None),
- cleaned=True,
- ),
- ],
- any_order=False, # Ensure calls are in the specified order
- )
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="chicken-liver.gov")
+ # trigger getter
+ _ = domain.statuses
+ status_list = [status.state for status in self.mockDataInfoDomain.statuses]
+ self.assertEquals(domain._cache["statuses"], status_list)
+ # Called in _fetch_cache
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(name="chicken-liver.gov", auth_info=None),
+ cleaned=True,
+ ),
+ ],
+ any_order=False, # Ensure calls are in the specified order
+ )
def test_get_status_returns_empty_list_when_value_error(self):
"""Domain 'statuses' getter returns an empty list
when value error"""
- domain, _ = Domain.objects.get_or_create(name="pig-knuckles.gov")
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="pig-knuckles.gov")
- def side_effect(self):
- raise KeyError
+ def side_effect(self):
+ raise KeyError
- patcher = patch("registrar.models.domain.Domain._get_property")
- mocked_get = patcher.start()
- mocked_get.side_effect = side_effect
+ patcher = patch("registrar.models.domain.Domain._get_property")
+ mocked_get = patcher.start()
+ mocked_get.side_effect = side_effect
- # trigger getter
- _ = domain.statuses
+ # trigger getter
+ _ = domain.statuses
- with self.assertRaises(KeyError):
- _ = domain._cache["statuses"]
- self.assertEquals(_, [])
+ with self.assertRaises(KeyError):
+ _ = domain._cache["statuses"]
+ self.assertEquals(_, [])
- patcher.stop()
+ patcher.stop()
@skip("not implemented yet")
def test_place_client_hold_sets_status(self):
@@ -398,28 +406,23 @@ class TestDomainStatuses(MockEppLib):
first_ready is set when a domain is first transitioned to READY. It does not get overwritten
in case the domain gets out of and back into READY.
"""
- domain, _ = Domain.objects.get_or_create(name="pig-knuckles.gov", state=Domain.State.DNS_NEEDED)
- self.assertEqual(domain.first_ready, None)
-
- domain.ready()
-
- # check that status is READY
- self.assertTrue(domain.is_active())
- self.assertNotEqual(domain.first_ready, None)
-
- # Capture the value of first_ready
- first_ready = domain.first_ready
-
- # change domain status
- domain.dns_needed()
- self.assertFalse(domain.is_active())
-
- # change back to READY
- domain.ready()
- self.assertTrue(domain.is_active())
-
- # assert that the value of first_ready has not changed
- self.assertEqual(domain.first_ready, first_ready)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="pig-knuckles.gov", state=Domain.State.DNS_NEEDED)
+ self.assertEqual(domain.first_ready, None)
+ domain.ready()
+ # check that status is READY
+ self.assertTrue(domain.is_active())
+ self.assertNotEqual(domain.first_ready, None)
+ # Capture the value of first_ready
+ first_ready = domain.first_ready
+ # change domain status
+ domain.dns_needed()
+ self.assertFalse(domain.is_active())
+ # change back to READY
+ domain.ready()
+ self.assertTrue(domain.is_active())
+ # assert that the value of first_ready has not changed
+ self.assertEqual(domain.first_ready, first_ready)
def tearDown(self) -> None:
PublicContact.objects.all().delete()
@@ -557,37 +560,32 @@ class TestRegistrantContacts(MockEppLib):
Then the domain has a valid security contact with CISA defaults
And disclose flags are set to keep the email address hidden
"""
-
- # making a domain should make it domain
- expectedSecContact = PublicContact.get_default_security()
- expectedSecContact.domain = self.domain
-
- self.domain.dns_needed_from_unknown()
-
- self.assertEqual(self.mockedSendFunction.call_count, 8)
- self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 4)
- self.assertEqual(
- PublicContact.objects.get(
+ with less_console_noise():
+ # making a domain should make it domain
+ expectedSecContact = PublicContact.get_default_security()
+ expectedSecContact.domain = self.domain
+ self.domain.dns_needed_from_unknown()
+ self.assertEqual(self.mockedSendFunction.call_count, 8)
+ self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 4)
+ self.assertEqual(
+ PublicContact.objects.get(
+ domain=self.domain,
+ contact_type=PublicContact.ContactTypeChoices.SECURITY,
+ ).email,
+ expectedSecContact.email,
+ )
+ id = PublicContact.objects.get(
domain=self.domain,
contact_type=PublicContact.ContactTypeChoices.SECURITY,
- ).email,
- expectedSecContact.email,
- )
-
- id = PublicContact.objects.get(
- domain=self.domain,
- contact_type=PublicContact.ContactTypeChoices.SECURITY,
- ).registry_id
-
- expectedSecContact.registry_id = id
- expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=False)
- expectedUpdateDomain = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=expectedSecContact.registry_id, type="security")],
- )
-
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
- self.mockedSendFunction.assert_any_call(expectedUpdateDomain, cleaned=True)
+ ).registry_id
+ expectedSecContact.registry_id = id
+ expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=False)
+ expectedUpdateDomain = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=expectedSecContact.registry_id, type="security")],
+ )
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ self.mockedSendFunction.assert_any_call(expectedUpdateDomain, cleaned=True)
def test_user_adds_security_email(self):
"""
@@ -598,35 +596,31 @@ class TestRegistrantContacts(MockEppLib):
And Domain sends `commands.UpdateDomain` to the registry with the newly
created contact of type 'security'
"""
- # make a security contact that is a PublicContact
- # make sure a security email already exists
- self.domain.dns_needed_from_unknown()
- expectedSecContact = PublicContact.get_default_security()
- expectedSecContact.domain = self.domain
- expectedSecContact.email = "newEmail@fake.com"
- expectedSecContact.registry_id = "456"
- expectedSecContact.name = "Fakey McFakerson"
-
- # calls the security contact setter as if you did
- # self.domain.security_contact=expectedSecContact
- expectedSecContact.save()
-
- # no longer the default email it should be disclosed
- expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=True)
-
- expectedUpdateDomain = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=expectedSecContact.registry_id, type="security")],
- )
-
- # check that send has triggered the create command for the contact
- receivedSecurityContact = PublicContact.objects.get(
- domain=self.domain, contact_type=PublicContact.ContactTypeChoices.SECURITY
- )
-
- self.assertEqual(receivedSecurityContact, expectedSecContact)
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
- self.mockedSendFunction.assert_any_call(expectedUpdateDomain, cleaned=True)
+ with less_console_noise():
+ # make a security contact that is a PublicContact
+ # make sure a security email already exists
+ self.domain.dns_needed_from_unknown()
+ expectedSecContact = PublicContact.get_default_security()
+ expectedSecContact.domain = self.domain
+ expectedSecContact.email = "newEmail@fake.com"
+ expectedSecContact.registry_id = "456"
+ expectedSecContact.name = "Fakey McFakerson"
+ # calls the security contact setter as if you did
+ # self.domain.security_contact=expectedSecContact
+ expectedSecContact.save()
+ # no longer the default email it should be disclosed
+ expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=True)
+ expectedUpdateDomain = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=expectedSecContact.registry_id, type="security")],
+ )
+ # check that send has triggered the create command for the contact
+ receivedSecurityContact = PublicContact.objects.get(
+ domain=self.domain, contact_type=PublicContact.ContactTypeChoices.SECURITY
+ )
+ self.assertEqual(receivedSecurityContact, expectedSecContact)
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ self.mockedSendFunction.assert_any_call(expectedUpdateDomain, cleaned=True)
def test_security_email_is_idempotent(self):
"""
@@ -635,26 +629,23 @@ class TestRegistrantContacts(MockEppLib):
to the registry twice with identical data
Then no errors are raised in Domain
"""
-
- security_contact = self.domain.get_default_security_contact()
- security_contact.registry_id = "fail"
- security_contact.save()
-
- self.domain.security_contact = security_contact
-
- expectedCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=False)
-
- expectedUpdateDomain = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=security_contact.registry_id, type="security")],
- )
- expected_calls = [
- call(expectedCreateCommand, cleaned=True),
- call(expectedCreateCommand, cleaned=True),
- call(expectedUpdateDomain, cleaned=True),
- ]
- self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
- self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 1)
+ with less_console_noise():
+ security_contact = self.domain.get_default_security_contact()
+ security_contact.registry_id = "fail"
+ security_contact.save()
+ self.domain.security_contact = security_contact
+ expectedCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=False)
+ expectedUpdateDomain = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=security_contact.registry_id, type="security")],
+ )
+ expected_calls = [
+ call(expectedCreateCommand, cleaned=True),
+ call(expectedCreateCommand, cleaned=True),
+ call(expectedUpdateDomain, cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
+ self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 1)
def test_user_deletes_security_email(self):
"""
@@ -667,51 +658,47 @@ class TestRegistrantContacts(MockEppLib):
And the domain has a valid security contact with CISA defaults
And disclose flags are set to keep the email address hidden
"""
- old_contact = self.domain.get_default_security_contact()
-
- old_contact.registry_id = "fail"
- old_contact.email = "user.entered@email.com"
- old_contact.save()
- new_contact = self.domain.get_default_security_contact()
- new_contact.registry_id = "fail"
- new_contact.email = ""
- self.domain.security_contact = new_contact
-
- firstCreateContactCall = self._convertPublicContactToEpp(old_contact, disclose_email=True)
- updateDomainAddCall = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=old_contact.registry_id, type="security")],
- )
- self.assertEqual(
- PublicContact.objects.filter(domain=self.domain).get().email,
- PublicContact.get_default_security().email,
- )
- # this one triggers the fail
- secondCreateContact = self._convertPublicContactToEpp(new_contact, disclose_email=True)
- updateDomainRemCall = commands.UpdateDomain(
- name=self.domain.name,
- rem=[common.DomainContact(contact=old_contact.registry_id, type="security")],
- )
-
- defaultSecID = PublicContact.objects.filter(domain=self.domain).get().registry_id
- default_security = PublicContact.get_default_security()
- default_security.registry_id = defaultSecID
- createDefaultContact = self._convertPublicContactToEpp(default_security, disclose_email=False)
- updateDomainWDefault = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=defaultSecID, type="security")],
- )
-
- expected_calls = [
- call(firstCreateContactCall, cleaned=True),
- call(updateDomainAddCall, cleaned=True),
- call(secondCreateContact, cleaned=True),
- call(updateDomainRemCall, cleaned=True),
- call(createDefaultContact, cleaned=True),
- call(updateDomainWDefault, cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
+ with less_console_noise():
+ old_contact = self.domain.get_default_security_contact()
+ old_contact.registry_id = "fail"
+ old_contact.email = "user.entered@email.com"
+ old_contact.save()
+ new_contact = self.domain.get_default_security_contact()
+ new_contact.registry_id = "fail"
+ new_contact.email = ""
+ self.domain.security_contact = new_contact
+ firstCreateContactCall = self._convertPublicContactToEpp(old_contact, disclose_email=True)
+ updateDomainAddCall = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=old_contact.registry_id, type="security")],
+ )
+ self.assertEqual(
+ PublicContact.objects.filter(domain=self.domain).get().email,
+ PublicContact.get_default_security().email,
+ )
+ # this one triggers the fail
+ secondCreateContact = self._convertPublicContactToEpp(new_contact, disclose_email=True)
+ updateDomainRemCall = commands.UpdateDomain(
+ name=self.domain.name,
+ rem=[common.DomainContact(contact=old_contact.registry_id, type="security")],
+ )
+ defaultSecID = PublicContact.objects.filter(domain=self.domain).get().registry_id
+ default_security = PublicContact.get_default_security()
+ default_security.registry_id = defaultSecID
+ createDefaultContact = self._convertPublicContactToEpp(default_security, disclose_email=False)
+ updateDomainWDefault = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=defaultSecID, type="security")],
+ )
+ expected_calls = [
+ call(firstCreateContactCall, cleaned=True),
+ call(updateDomainAddCall, cleaned=True),
+ call(secondCreateContact, cleaned=True),
+ call(updateDomainRemCall, cleaned=True),
+ call(createDefaultContact, cleaned=True),
+ call(updateDomainWDefault, cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
def test_updates_security_email(self):
"""
@@ -721,29 +708,28 @@ class TestRegistrantContacts(MockEppLib):
security contact email
Then Domain sends `commands.UpdateContact` to the registry
"""
- security_contact = self.domain.get_default_security_contact()
- security_contact.email = "originalUserEmail@gmail.com"
- security_contact.registry_id = "fail"
- security_contact.save()
- expectedCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=True)
-
- expectedUpdateDomain = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.DomainContact(contact=security_contact.registry_id, type="security")],
- )
- security_contact.email = "changedEmail@email.com"
- security_contact.save()
- expectedSecondCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=True)
- updateContact = self._convertPublicContactToEpp(security_contact, disclose_email=True, createContact=False)
-
- expected_calls = [
- call(expectedCreateCommand, cleaned=True),
- call(expectedUpdateDomain, cleaned=True),
- call(expectedSecondCreateCommand, cleaned=True),
- call(updateContact, cleaned=True),
- ]
- self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
- self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 1)
+ with less_console_noise():
+ security_contact = self.domain.get_default_security_contact()
+ security_contact.email = "originalUserEmail@gmail.com"
+ security_contact.registry_id = "fail"
+ security_contact.save()
+ expectedCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=True)
+ expectedUpdateDomain = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.DomainContact(contact=security_contact.registry_id, type="security")],
+ )
+ security_contact.email = "changedEmail@email.com"
+ security_contact.save()
+ expectedSecondCreateCommand = self._convertPublicContactToEpp(security_contact, disclose_email=True)
+ updateContact = self._convertPublicContactToEpp(security_contact, disclose_email=True, createContact=False)
+ expected_calls = [
+ call(expectedCreateCommand, cleaned=True),
+ call(expectedUpdateDomain, cleaned=True),
+ call(expectedSecondCreateCommand, cleaned=True),
+ call(updateContact, cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expected_calls, any_order=True)
+ self.assertEqual(PublicContact.objects.filter(domain=self.domain).count(), 1)
def test_security_email_returns_on_registry_error(self):
"""
@@ -751,28 +737,26 @@ class TestRegistrantContacts(MockEppLib):
Registry is unavailable and throws exception when attempting to build cache from
registry. Security email retrieved from database.
"""
- # Use self.domain_contact which has been initialized with existing contacts, including securityContact
+ with less_console_noise():
+ # Use self.domain_contact which has been initialized with existing contacts, including securityContact
+ # call get_security_email to initially set the security_contact_registry_id in the domain model
+ self.domain_contact.get_security_email()
+ # invalidate the cache so the next time get_security_email is called, it has to attempt to populate cache
+ self.domain_contact._invalidate_cache()
- # call get_security_email to initially set the security_contact_registry_id in the domain model
- self.domain_contact.get_security_email()
- # invalidate the cache so the next time get_security_email is called, it has to attempt to populate cache
- self.domain_contact._invalidate_cache()
+ # mock that registry throws an error on the EPP send
+ def side_effect(_request, cleaned):
+ raise RegistryError(code=ErrorCode.COMMAND_FAILED)
- # mock that registry throws an error on the EPP send
- def side_effect(_request, cleaned):
- raise RegistryError(code=ErrorCode.COMMAND_FAILED)
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- # when get_security_email is called, the registry error will force the security contact
- # to be retrieved using the security_contact_registry_id in the domain model
- security_email = self.domain_contact.get_security_email()
-
- # assert that the proper security contact was retrieved by testing the email matches expected value
- self.assertEqual(security_email, "security@mail.gov")
- patcher.stop()
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ # when get_security_email is called, the registry error will force the security contact
+ # to be retrieved using the security_contact_registry_id in the domain model
+ security_email = self.domain_contact.get_security_email()
+ # assert that the proper security contact was retrieved by testing the email matches expected value
+ self.assertEqual(security_email, "security@mail.gov")
+ patcher.stop()
def test_security_email_stored_on_fetch_cache(self):
"""
@@ -781,13 +765,14 @@ class TestRegistrantContacts(MockEppLib):
The mocked data for the EPP calls for the freeman.gov domain returns a security
contact with registry id of securityContact when InfoContact is called
"""
- # Use self.domain_contact which has been initialized with existing contacts, including securityContact
+ with less_console_noise():
+ # Use self.domain_contact which has been initialized with existing contacts, including securityContact
- # force fetch_cache to be called, which will return above documented mocked hosts
- self.domain_contact.get_security_email()
+ # force fetch_cache to be called, which will return above documented mocked hosts
+ self.domain_contact.get_security_email()
- # assert that the security_contact_registry_id in the db matches "securityContact"
- self.assertEqual(self.domain_contact.security_contact_registry_id, "securityContact")
+ # assert that the security_contact_registry_id in the db matches "securityContact"
+ self.assertEqual(self.domain_contact.security_contact_registry_id, "securityContact")
def test_not_disclosed_on_other_contacts(self):
"""
@@ -798,113 +783,101 @@ class TestRegistrantContacts(MockEppLib):
And the field `disclose` is set to false for DF.EMAIL
on all fields except security
"""
- # Generates a domain with four existing contacts
- domain, _ = Domain.objects.get_or_create(name="freeman.gov")
-
- # Contact setup
- expected_admin = domain.get_default_administrative_contact()
- expected_admin.email = self.mockAdministrativeContact.email
-
- expected_registrant = domain.get_default_registrant_contact()
- expected_registrant.email = self.mockRegistrantContact.email
-
- expected_security = domain.get_default_security_contact()
- expected_security.email = self.mockSecurityContact.email
-
- expected_tech = domain.get_default_technical_contact()
- expected_tech.email = self.mockTechnicalContact.email
-
- domain.administrative_contact = expected_admin
- domain.registrant_contact = expected_registrant
- domain.security_contact = expected_security
- domain.technical_contact = expected_tech
-
- contacts = [
- (expected_admin, domain.administrative_contact),
- (expected_registrant, domain.registrant_contact),
- (expected_security, domain.security_contact),
- (expected_tech, domain.technical_contact),
- ]
-
- # Test for each contact
- for contact in contacts:
- expected_contact = contact[0]
- actual_contact = contact[1]
- is_security = expected_contact.contact_type == "security"
-
- expectedCreateCommand = self._convertPublicContactToEpp(expected_contact, disclose_email=is_security)
-
- # Should only be disclosed if the type is security, as the email is valid
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
-
- # The emails should match on both items
- self.assertEqual(expected_contact.email, actual_contact.email)
+ with less_console_noise():
+ # Generates a domain with four existing contacts
+ domain, _ = Domain.objects.get_or_create(name="freeman.gov")
+ # Contact setup
+ expected_admin = domain.get_default_administrative_contact()
+ expected_admin.email = self.mockAdministrativeContact.email
+ expected_registrant = domain.get_default_registrant_contact()
+ expected_registrant.email = self.mockRegistrantContact.email
+ expected_security = domain.get_default_security_contact()
+ expected_security.email = self.mockSecurityContact.email
+ expected_tech = domain.get_default_technical_contact()
+ expected_tech.email = self.mockTechnicalContact.email
+ domain.administrative_contact = expected_admin
+ domain.registrant_contact = expected_registrant
+ domain.security_contact = expected_security
+ domain.technical_contact = expected_tech
+ contacts = [
+ (expected_admin, domain.administrative_contact),
+ (expected_registrant, domain.registrant_contact),
+ (expected_security, domain.security_contact),
+ (expected_tech, domain.technical_contact),
+ ]
+ # Test for each contact
+ for contact in contacts:
+ expected_contact = contact[0]
+ actual_contact = contact[1]
+ is_security = expected_contact.contact_type == "security"
+ expectedCreateCommand = self._convertPublicContactToEpp(expected_contact, disclose_email=is_security)
+ # Should only be disclosed if the type is security, as the email is valid
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ # The emails should match on both items
+ self.assertEqual(expected_contact.email, actual_contact.email)
def test_convert_public_contact_to_epp(self):
- domain, _ = Domain.objects.get_or_create(name="freeman.gov")
- dummy_contact = domain.get_default_security_contact()
- test_disclose = self._convertPublicContactToEpp(dummy_contact, disclose_email=True).__dict__
- test_not_disclose = self._convertPublicContactToEpp(dummy_contact, disclose_email=False).__dict__
-
- # Separated for linter
- disclose_email_field = {common.DiscloseField.EMAIL}
- expected_disclose = {
- "auth_info": common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
- "disclose": common.Disclose(flag=True, fields=disclose_email_field, types=None),
- "email": "dotgov@cisa.dhs.gov",
- "extensions": [],
- "fax": None,
- "id": "ThIq2NcRIDN7PauO",
- "ident": None,
- "notify_email": None,
- "postal_info": common.PostalInfo(
- name="Registry Customer Service",
- addr=common.ContactAddr(
- street=["4200 Wilson Blvd.", None, None],
- city="Arlington",
- pc="22201",
- cc="US",
- sp="VA",
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="freeman.gov")
+ dummy_contact = domain.get_default_security_contact()
+ test_disclose = self._convertPublicContactToEpp(dummy_contact, disclose_email=True).__dict__
+ test_not_disclose = self._convertPublicContactToEpp(dummy_contact, disclose_email=False).__dict__
+ # Separated for linter
+ disclose_email_field = {common.DiscloseField.EMAIL}
+ expected_disclose = {
+ "auth_info": common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
+ "disclose": common.Disclose(flag=True, fields=disclose_email_field, types=None),
+ "email": "dotgov@cisa.dhs.gov",
+ "extensions": [],
+ "fax": None,
+ "id": "ThIq2NcRIDN7PauO",
+ "ident": None,
+ "notify_email": None,
+ "postal_info": common.PostalInfo(
+ name="Registry Customer Service",
+ addr=common.ContactAddr(
+ street=["4200 Wilson Blvd.", None, None],
+ city="Arlington",
+ pc="22201",
+ cc="US",
+ sp="VA",
+ ),
+ org="Cybersecurity and Infrastructure Security Agency",
+ type="loc",
),
- org="Cybersecurity and Infrastructure Security Agency",
- type="loc",
- ),
- "vat": None,
- "voice": "+1.8882820870",
- }
-
- # Separated for linter
- expected_not_disclose = {
- "auth_info": common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
- "disclose": common.Disclose(flag=False, fields=disclose_email_field, types=None),
- "email": "dotgov@cisa.dhs.gov",
- "extensions": [],
- "fax": None,
- "id": "ThrECENCHI76PGLh",
- "ident": None,
- "notify_email": None,
- "postal_info": common.PostalInfo(
- name="Registry Customer Service",
- addr=common.ContactAddr(
- street=["4200 Wilson Blvd.", None, None],
- city="Arlington",
- pc="22201",
- cc="US",
- sp="VA",
+ "vat": None,
+ "voice": "+1.8882820870",
+ }
+ # Separated for linter
+ expected_not_disclose = {
+ "auth_info": common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
+ "disclose": common.Disclose(flag=False, fields=disclose_email_field, types=None),
+ "email": "dotgov@cisa.dhs.gov",
+ "extensions": [],
+ "fax": None,
+ "id": "ThrECENCHI76PGLh",
+ "ident": None,
+ "notify_email": None,
+ "postal_info": common.PostalInfo(
+ name="Registry Customer Service",
+ addr=common.ContactAddr(
+ street=["4200 Wilson Blvd.", None, None],
+ city="Arlington",
+ pc="22201",
+ cc="US",
+ sp="VA",
+ ),
+ org="Cybersecurity and Infrastructure Security Agency",
+ type="loc",
),
- org="Cybersecurity and Infrastructure Security Agency",
- type="loc",
- ),
- "vat": None,
- "voice": "+1.8882820870",
- }
-
- # Set the ids equal, since this value changes
- test_disclose["id"] = expected_disclose["id"]
- test_not_disclose["id"] = expected_not_disclose["id"]
-
- self.assertEqual(test_disclose, expected_disclose)
- self.assertEqual(test_not_disclose, expected_not_disclose)
+ "vat": None,
+ "voice": "+1.8882820870",
+ }
+ # Set the ids equal, since this value changes
+ test_disclose["id"] = expected_disclose["id"]
+ test_not_disclose["id"] = expected_not_disclose["id"]
+ self.assertEqual(test_disclose, expected_disclose)
+ self.assertEqual(test_not_disclose, expected_not_disclose)
def test_not_disclosed_on_default_security_contact(self):
"""
@@ -913,17 +886,16 @@ class TestRegistrantContacts(MockEppLib):
Then Domain sends `commands.CreateContact` to the registry
And the field `disclose` is set to false for DF.EMAIL
"""
- domain, _ = Domain.objects.get_or_create(name="defaultsecurity.gov")
- expectedSecContact = PublicContact.get_default_security()
- expectedSecContact.domain = domain
- expectedSecContact.registry_id = "defaultSec"
- domain.security_contact = expectedSecContact
-
- expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=False)
-
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
- # Confirm that we are getting a default email
- self.assertEqual(domain.security_contact.email, expectedSecContact.email)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="defaultsecurity.gov")
+ expectedSecContact = PublicContact.get_default_security()
+ expectedSecContact.domain = domain
+ expectedSecContact.registry_id = "defaultSec"
+ domain.security_contact = expectedSecContact
+ expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=False)
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ # Confirm that we are getting a default email
+ self.assertEqual(domain.security_contact.email, expectedSecContact.email)
def test_not_disclosed_on_default_technical_contact(self):
"""
@@ -932,17 +904,16 @@ class TestRegistrantContacts(MockEppLib):
Then Domain sends `commands.CreateContact` to the registry
And the field `disclose` is set to false for DF.EMAIL
"""
- domain, _ = Domain.objects.get_or_create(name="defaulttechnical.gov")
- expectedTechContact = PublicContact.get_default_technical()
- expectedTechContact.domain = domain
- expectedTechContact.registry_id = "defaultTech"
- domain.technical_contact = expectedTechContact
-
- expectedCreateCommand = self._convertPublicContactToEpp(expectedTechContact, disclose_email=False)
-
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
- # Confirm that we are getting a default email
- self.assertEqual(domain.technical_contact.email, expectedTechContact.email)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="defaulttechnical.gov")
+ expectedTechContact = PublicContact.get_default_technical()
+ expectedTechContact.domain = domain
+ expectedTechContact.registry_id = "defaultTech"
+ domain.technical_contact = expectedTechContact
+ expectedCreateCommand = self._convertPublicContactToEpp(expectedTechContact, disclose_email=False)
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ # Confirm that we are getting a default email
+ self.assertEqual(domain.technical_contact.email, expectedTechContact.email)
def test_is_disclosed_on_security_contact(self):
"""
@@ -952,17 +923,16 @@ class TestRegistrantContacts(MockEppLib):
Then Domain sends `commands.CreateContact` to the registry
And the field `disclose` is set to true for DF.EMAIL
"""
- domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- expectedSecContact = PublicContact.get_default_security()
- expectedSecContact.domain = domain
- expectedSecContact.email = "123@mail.gov"
- domain.security_contact = expectedSecContact
-
- expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=True)
-
- self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
- # Confirm that we are getting the desired email
- self.assertEqual(domain.security_contact.email, expectedSecContact.email)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ expectedSecContact = PublicContact.get_default_security()
+ expectedSecContact.domain = domain
+ expectedSecContact.email = "123@mail.gov"
+ domain.security_contact = expectedSecContact
+ expectedCreateCommand = self._convertPublicContactToEpp(expectedSecContact, disclose_email=True)
+ self.mockedSendFunction.assert_any_call(expectedCreateCommand, cleaned=True)
+ # Confirm that we are getting the desired email
+ self.assertEqual(domain.security_contact.email, expectedSecContact.email)
@skip("not implemented yet")
def test_update_is_unsuccessful(self):
@@ -974,121 +944,112 @@ class TestRegistrantContacts(MockEppLib):
raise
def test_contact_getter_security(self):
- security = PublicContact.ContactTypeChoices.SECURITY
- # Create prexisting object
- expected_contact = self.domain.map_epp_contact_to_public_contact(
- self.mockSecurityContact,
- contact_id="securityContact",
- contact_type=security,
- )
-
- # Checks if we grabbed the correct PublicContact
- self.assertEqual(self.domain_contact.security_contact.email, expected_contact.email)
-
- expected_contact_db = PublicContact.objects.filter(
- registry_id=self.domain_contact.security_contact.registry_id,
- contact_type=security,
- ).get()
-
- self.assertEqual(self.domain_contact.security_contact, expected_contact_db)
-
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoContact(id="securityContact", auth_info=None),
- cleaned=True,
- ),
- ]
- )
- # Checks if we are receiving the cache we expect
- cache = self.domain_contact._cache["contacts"]
- self.assertEqual(cache.get(security), "securityContact")
+ with less_console_noise():
+ security = PublicContact.ContactTypeChoices.SECURITY
+ # Create prexisting object
+ expected_contact = self.domain.map_epp_contact_to_public_contact(
+ self.mockSecurityContact,
+ contact_id="securityContact",
+ contact_type=security,
+ )
+ # Checks if we grabbed the correct PublicContact
+ self.assertEqual(self.domain_contact.security_contact.email, expected_contact.email)
+ expected_contact_db = PublicContact.objects.filter(
+ registry_id=self.domain_contact.security_contact.registry_id,
+ contact_type=security,
+ ).get()
+ self.assertEqual(self.domain_contact.security_contact, expected_contact_db)
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoContact(id="securityContact", auth_info=None),
+ cleaned=True,
+ ),
+ ]
+ )
+ # Checks if we are receiving the cache we expect
+ cache = self.domain_contact._cache["contacts"]
+ self.assertEqual(cache.get(security), "securityContact")
def test_contact_getter_technical(self):
- technical = PublicContact.ContactTypeChoices.TECHNICAL
- expected_contact = self.domain.map_epp_contact_to_public_contact(
- self.mockTechnicalContact,
- contact_id="technicalContact",
- contact_type=technical,
- )
-
- self.assertEqual(self.domain_contact.technical_contact.email, expected_contact.email)
-
- # Checks if we grab the correct PublicContact
- expected_contact_db = PublicContact.objects.filter(
- registry_id=self.domain_contact.technical_contact.registry_id,
- contact_type=technical,
- ).get()
-
- # Checks if we grab the correct PublicContact
- self.assertEqual(self.domain_contact.technical_contact, expected_contact_db)
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoContact(id="technicalContact", auth_info=None),
- cleaned=True,
- ),
- ]
- )
- # Checks if we are receiving the cache we expect
- cache = self.domain_contact._cache["contacts"]
- self.assertEqual(cache.get(technical), "technicalContact")
+ with less_console_noise():
+ technical = PublicContact.ContactTypeChoices.TECHNICAL
+ expected_contact = self.domain.map_epp_contact_to_public_contact(
+ self.mockTechnicalContact,
+ contact_id="technicalContact",
+ contact_type=technical,
+ )
+ self.assertEqual(self.domain_contact.technical_contact.email, expected_contact.email)
+ # Checks if we grab the correct PublicContact
+ expected_contact_db = PublicContact.objects.filter(
+ registry_id=self.domain_contact.technical_contact.registry_id,
+ contact_type=technical,
+ ).get()
+ # Checks if we grab the correct PublicContact
+ self.assertEqual(self.domain_contact.technical_contact, expected_contact_db)
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoContact(id="technicalContact", auth_info=None),
+ cleaned=True,
+ ),
+ ]
+ )
+ # Checks if we are receiving the cache we expect
+ cache = self.domain_contact._cache["contacts"]
+ self.assertEqual(cache.get(technical), "technicalContact")
def test_contact_getter_administrative(self):
- administrative = PublicContact.ContactTypeChoices.ADMINISTRATIVE
- expected_contact = self.domain.map_epp_contact_to_public_contact(
- self.mockAdministrativeContact,
- contact_id="adminContact",
- contact_type=administrative,
- )
-
- self.assertEqual(self.domain_contact.administrative_contact.email, expected_contact.email)
-
- expected_contact_db = PublicContact.objects.filter(
- registry_id=self.domain_contact.administrative_contact.registry_id,
- contact_type=administrative,
- ).get()
-
- # Checks if we grab the correct PublicContact
- self.assertEqual(self.domain_contact.administrative_contact, expected_contact_db)
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoContact(id="adminContact", auth_info=None),
- cleaned=True,
- ),
- ]
- )
- # Checks if we are receiving the cache we expect
- cache = self.domain_contact._cache["contacts"]
- self.assertEqual(cache.get(administrative), "adminContact")
+ with less_console_noise():
+ administrative = PublicContact.ContactTypeChoices.ADMINISTRATIVE
+ expected_contact = self.domain.map_epp_contact_to_public_contact(
+ self.mockAdministrativeContact,
+ contact_id="adminContact",
+ contact_type=administrative,
+ )
+ self.assertEqual(self.domain_contact.administrative_contact.email, expected_contact.email)
+ expected_contact_db = PublicContact.objects.filter(
+ registry_id=self.domain_contact.administrative_contact.registry_id,
+ contact_type=administrative,
+ ).get()
+ # Checks if we grab the correct PublicContact
+ self.assertEqual(self.domain_contact.administrative_contact, expected_contact_db)
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoContact(id="adminContact", auth_info=None),
+ cleaned=True,
+ ),
+ ]
+ )
+ # Checks if we are receiving the cache we expect
+ cache = self.domain_contact._cache["contacts"]
+ self.assertEqual(cache.get(administrative), "adminContact")
def test_contact_getter_registrant(self):
- expected_contact = self.domain.map_epp_contact_to_public_contact(
- self.mockRegistrantContact,
- contact_id="regContact",
- contact_type=PublicContact.ContactTypeChoices.REGISTRANT,
- )
-
- self.assertEqual(self.domain_contact.registrant_contact.email, expected_contact.email)
-
- expected_contact_db = PublicContact.objects.filter(
- registry_id=self.domain_contact.registrant_contact.registry_id,
- contact_type=PublicContact.ContactTypeChoices.REGISTRANT,
- ).get()
-
- # Checks if we grab the correct PublicContact
- self.assertEqual(self.domain_contact.registrant_contact, expected_contact_db)
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.InfoContact(id="regContact", auth_info=None),
- cleaned=True,
- ),
- ]
- )
- # Checks if we are receiving the cache we expect.
- self.assertEqual(self.domain_contact._cache["registrant"], expected_contact_db)
+ with less_console_noise():
+ expected_contact = self.domain.map_epp_contact_to_public_contact(
+ self.mockRegistrantContact,
+ contact_id="regContact",
+ contact_type=PublicContact.ContactTypeChoices.REGISTRANT,
+ )
+ self.assertEqual(self.domain_contact.registrant_contact.email, expected_contact.email)
+ expected_contact_db = PublicContact.objects.filter(
+ registry_id=self.domain_contact.registrant_contact.registry_id,
+ contact_type=PublicContact.ContactTypeChoices.REGISTRANT,
+ ).get()
+ # Checks if we grab the correct PublicContact
+ self.assertEqual(self.domain_contact.registrant_contact, expected_contact_db)
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoContact(id="regContact", auth_info=None),
+ cleaned=True,
+ ),
+ ]
+ )
+ # Checks if we are receiving the cache we expect.
+ self.assertEqual(self.domain_contact._cache["registrant"], expected_contact_db)
class TestRegistrantNameservers(MockEppLib):
@@ -1112,76 +1073,78 @@ class TestRegistrantNameservers(MockEppLib):
def test_get_nameserver_changes_success_deleted_vals(self):
"""Testing only deleting and no other changes"""
- self.domain._cache["hosts"] = [
- {"name": "ns1.example.com", "addrs": None},
- {"name": "ns2.example.com", "addrs": ["1.2.3.4"]},
- ]
- newChanges = [
- ("ns1.example.com",),
- ]
- (
- deleted_values,
- updated_values,
- new_values,
- oldNameservers,
- ) = self.domain.getNameserverChanges(newChanges)
+ with less_console_noise():
+ self.domain._cache["hosts"] = [
+ {"name": "ns1.example.com", "addrs": None},
+ {"name": "ns2.example.com", "addrs": ["1.2.3.4"]},
+ ]
+ newChanges = [
+ ("ns1.example.com",),
+ ]
+ (
+ deleted_values,
+ updated_values,
+ new_values,
+ oldNameservers,
+ ) = self.domain.getNameserverChanges(newChanges)
- self.assertEqual(deleted_values, ["ns2.example.com"])
- self.assertEqual(updated_values, [])
- self.assertEqual(new_values, {})
- self.assertEqual(
- oldNameservers,
- {"ns1.example.com": None, "ns2.example.com": ["1.2.3.4"]},
- )
+ self.assertEqual(deleted_values, ["ns2.example.com"])
+ self.assertEqual(updated_values, [])
+ self.assertEqual(new_values, {})
+ self.assertEqual(
+ oldNameservers,
+ {"ns1.example.com": None, "ns2.example.com": ["1.2.3.4"]},
+ )
def test_get_nameserver_changes_success_updated_vals(self):
"""Testing only updating no other changes"""
- self.domain._cache["hosts"] = [
- {"name": "ns3.my-nameserver.gov", "addrs": ["1.2.3.4"]},
- ]
- newChanges = [
- ("ns3.my-nameserver.gov", ["1.2.4.5"]),
- ]
- (
- deleted_values,
- updated_values,
- new_values,
- oldNameservers,
- ) = self.domain.getNameserverChanges(newChanges)
-
- self.assertEqual(deleted_values, [])
- self.assertEqual(updated_values, [("ns3.my-nameserver.gov", ["1.2.4.5"])])
- self.assertEqual(new_values, {})
- self.assertEqual(
- oldNameservers,
- {"ns3.my-nameserver.gov": ["1.2.3.4"]},
- )
+ with less_console_noise():
+ self.domain._cache["hosts"] = [
+ {"name": "ns3.my-nameserver.gov", "addrs": ["1.2.3.4"]},
+ ]
+ newChanges = [
+ ("ns3.my-nameserver.gov", ["1.2.4.5"]),
+ ]
+ (
+ deleted_values,
+ updated_values,
+ new_values,
+ oldNameservers,
+ ) = self.domain.getNameserverChanges(newChanges)
+ self.assertEqual(deleted_values, [])
+ self.assertEqual(updated_values, [("ns3.my-nameserver.gov", ["1.2.4.5"])])
+ self.assertEqual(new_values, {})
+ self.assertEqual(
+ oldNameservers,
+ {"ns3.my-nameserver.gov": ["1.2.3.4"]},
+ )
def test_get_nameserver_changes_success_new_vals(self):
- # Testing only creating no other changes
- self.domain._cache["hosts"] = [
- {"name": "ns1.example.com", "addrs": None},
- ]
- newChanges = [
- ("ns1.example.com",),
- ("ns4.example.com",),
- ]
- (
- deleted_values,
- updated_values,
- new_values,
- oldNameservers,
- ) = self.domain.getNameserverChanges(newChanges)
+ with less_console_noise():
+ # Testing only creating no other changes
+ self.domain._cache["hosts"] = [
+ {"name": "ns1.example.com", "addrs": None},
+ ]
+ newChanges = [
+ ("ns1.example.com",),
+ ("ns4.example.com",),
+ ]
+ (
+ deleted_values,
+ updated_values,
+ new_values,
+ oldNameservers,
+ ) = self.domain.getNameserverChanges(newChanges)
- self.assertEqual(deleted_values, [])
- self.assertEqual(updated_values, [])
- self.assertEqual(new_values, {"ns4.example.com": None})
- self.assertEqual(
- oldNameservers,
- {
- "ns1.example.com": None,
- },
- )
+ self.assertEqual(deleted_values, [])
+ self.assertEqual(updated_values, [])
+ self.assertEqual(new_values, {"ns4.example.com": None})
+ self.assertEqual(
+ oldNameservers,
+ {
+ "ns1.example.com": None,
+ },
+ )
def test_user_adds_one_nameserver(self):
"""
@@ -1193,32 +1156,27 @@ class TestRegistrantNameservers(MockEppLib):
And `domain.is_active` returns False
And domain.first_ready is null
"""
-
- # set 1 nameserver
- nameserver = "ns1.my-nameserver.com"
- self.domain.nameservers = [(nameserver,)]
-
- # when we create a host, we should've updated at the same time
- created_host = commands.CreateHost(nameserver)
- update_domain_with_created = commands.UpdateDomain(
- name=self.domain.name,
- add=[common.HostObjSet([created_host.name])],
- rem=[],
- )
-
- # checking if commands were sent (commands have to be sent in order)
- expectedCalls = [
- call(created_host, cleaned=True),
- call(update_domain_with_created, cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls)
-
- # check that status is still NOT READY
- # as you have less than 2 nameservers
- self.assertFalse(self.domain.is_active())
-
- self.assertEqual(self.domain.first_ready, None)
+ with less_console_noise():
+ # set 1 nameserver
+ nameserver = "ns1.my-nameserver.com"
+ self.domain.nameservers = [(nameserver,)]
+ # when we create a host, we should've updated at the same time
+ created_host = commands.CreateHost(nameserver)
+ update_domain_with_created = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[common.HostObjSet([created_host.name])],
+ rem=[],
+ )
+ # checking if commands were sent (commands have to be sent in order)
+ expectedCalls = [
+ call(created_host, cleaned=True),
+ call(update_domain_with_created, cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls)
+ # check that status is still NOT READY
+ # as you have less than 2 nameservers
+ self.assertFalse(self.domain.is_active())
+ self.assertEqual(self.domain.first_ready, None)
def test_user_adds_two_nameservers(self):
"""
@@ -1230,36 +1188,32 @@ class TestRegistrantNameservers(MockEppLib):
And `domain.is_active` returns True
And domain.first_ready is not null
"""
-
- # set 2 nameservers
- self.domain.nameservers = [(self.nameserver1,), (self.nameserver2,)]
-
- # when you create a host, you also have to update at same time
- created_host1 = commands.CreateHost(self.nameserver1)
- created_host2 = commands.CreateHost(self.nameserver2)
-
- update_domain_with_created = commands.UpdateDomain(
- name=self.domain.name,
- add=[
- common.HostObjSet([created_host1.name, created_host2.name]),
- ],
- rem=[],
- )
-
- infoDomain = commands.InfoDomain(name="my-nameserver.gov", auth_info=None)
- # checking if commands were sent (commands have to be sent in order)
- expectedCalls = [
- call(infoDomain, cleaned=True),
- call(created_host1, cleaned=True),
- call(created_host2, cleaned=True),
- call(update_domain_with_created, cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertEqual(4, self.mockedSendFunction.call_count)
- # check that status is READY
- self.assertTrue(self.domain.is_active())
- self.assertNotEqual(self.domain.first_ready, None)
+ with less_console_noise():
+ # set 2 nameservers
+ self.domain.nameservers = [(self.nameserver1,), (self.nameserver2,)]
+ # when you create a host, you also have to update at same time
+ created_host1 = commands.CreateHost(self.nameserver1)
+ created_host2 = commands.CreateHost(self.nameserver2)
+ update_domain_with_created = commands.UpdateDomain(
+ name=self.domain.name,
+ add=[
+ common.HostObjSet([created_host1.name, created_host2.name]),
+ ],
+ rem=[],
+ )
+ infoDomain = commands.InfoDomain(name="my-nameserver.gov", auth_info=None)
+ # checking if commands were sent (commands have to be sent in order)
+ expectedCalls = [
+ call(infoDomain, cleaned=True),
+ call(created_host1, cleaned=True),
+ call(created_host2, cleaned=True),
+ call(update_domain_with_created, cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertEqual(4, self.mockedSendFunction.call_count)
+ # check that status is READY
+ self.assertTrue(self.domain.is_active())
+ self.assertNotEqual(self.domain.first_ready, None)
def test_user_adds_too_many_nameservers(self):
"""
@@ -1268,43 +1222,43 @@ class TestRegistrantNameservers(MockEppLib):
When `domain.nameservers` is set to an array of length 14
Then Domain raises a user-friendly error
"""
+ with less_console_noise():
+ # set 13+ nameservers
+ nameserver1 = "ns1.cats-are-superior1.com"
+ nameserver2 = "ns1.cats-are-superior2.com"
+ nameserver3 = "ns1.cats-are-superior3.com"
+ nameserver4 = "ns1.cats-are-superior4.com"
+ nameserver5 = "ns1.cats-are-superior5.com"
+ nameserver6 = "ns1.cats-are-superior6.com"
+ nameserver7 = "ns1.cats-are-superior7.com"
+ nameserver8 = "ns1.cats-are-superior8.com"
+ nameserver9 = "ns1.cats-are-superior9.com"
+ nameserver10 = "ns1.cats-are-superior10.com"
+ nameserver11 = "ns1.cats-are-superior11.com"
+ nameserver12 = "ns1.cats-are-superior12.com"
+ nameserver13 = "ns1.cats-are-superior13.com"
+ nameserver14 = "ns1.cats-are-superior14.com"
- # set 13+ nameservers
- nameserver1 = "ns1.cats-are-superior1.com"
- nameserver2 = "ns1.cats-are-superior2.com"
- nameserver3 = "ns1.cats-are-superior3.com"
- nameserver4 = "ns1.cats-are-superior4.com"
- nameserver5 = "ns1.cats-are-superior5.com"
- nameserver6 = "ns1.cats-are-superior6.com"
- nameserver7 = "ns1.cats-are-superior7.com"
- nameserver8 = "ns1.cats-are-superior8.com"
- nameserver9 = "ns1.cats-are-superior9.com"
- nameserver10 = "ns1.cats-are-superior10.com"
- nameserver11 = "ns1.cats-are-superior11.com"
- nameserver12 = "ns1.cats-are-superior12.com"
- nameserver13 = "ns1.cats-are-superior13.com"
- nameserver14 = "ns1.cats-are-superior14.com"
+ def _get_14_nameservers():
+ self.domain.nameservers = [
+ (nameserver1,),
+ (nameserver2,),
+ (nameserver3,),
+ (nameserver4,),
+ (nameserver5,),
+ (nameserver6,),
+ (nameserver7,),
+ (nameserver8,),
+ (nameserver9),
+ (nameserver10,),
+ (nameserver11,),
+ (nameserver12,),
+ (nameserver13,),
+ (nameserver14,),
+ ]
- def _get_14_nameservers():
- self.domain.nameservers = [
- (nameserver1,),
- (nameserver2,),
- (nameserver3,),
- (nameserver4,),
- (nameserver5,),
- (nameserver6,),
- (nameserver7,),
- (nameserver8,),
- (nameserver9),
- (nameserver10,),
- (nameserver11,),
- (nameserver12,),
- (nameserver13,),
- (nameserver14,),
- ]
-
- self.assertRaises(NameserverError, _get_14_nameservers)
- self.assertEqual(self.mockedSendFunction.call_count, 0)
+ self.assertRaises(NameserverError, _get_14_nameservers)
+ self.assertEqual(self.mockedSendFunction.call_count, 0)
def test_user_removes_some_nameservers(self):
"""
@@ -1315,37 +1269,36 @@ class TestRegistrantNameservers(MockEppLib):
to the registry
And `domain.is_active` returns True
"""
-
- # Mock is set to return 3 nameservers on infodomain
- self.domainWithThreeNS.nameservers = [(self.nameserver1,), (self.nameserver2,)]
- expectedCalls = [
- # calls info domain, and info on all hosts
- # to get past values
- # then removes the single host and updates domain
- call(
- commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
- cleaned=True,
- ),
- call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- call(
- commands.UpdateDomain(
- name=self.domainWithThreeNS.name,
- add=[],
- rem=[common.HostObjSet(hosts=["ns1.cats-are-superior3.com"])],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ with less_console_noise():
+ # Mock is set to return 3 nameservers on infodomain
+ self.domainWithThreeNS.nameservers = [(self.nameserver1,), (self.nameserver2,)]
+ expectedCalls = [
+ # calls info domain, and info on all hosts
+ # to get past values
+ # then removes the single host and updates domain
+ call(
+ commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(commands.DeleteHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertTrue(self.domainWithThreeNS.is_active())
+ call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ call(
+ commands.UpdateDomain(
+ name=self.domainWithThreeNS.name,
+ add=[],
+ rem=[common.HostObjSet(hosts=["ns1.cats-are-superior3.com"])],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
+ call(commands.DeleteHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertTrue(self.domainWithThreeNS.is_active())
def test_user_removes_too_many_nameservers(self):
"""
@@ -1357,41 +1310,40 @@ class TestRegistrantNameservers(MockEppLib):
And `domain.is_active` returns False
"""
-
- self.domainWithThreeNS.nameservers = [(self.nameserver1,)]
- expectedCalls = [
- call(
- commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
- cleaned=True,
- ),
- call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- call(commands.DeleteHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(
- commands.UpdateDomain(
- name=self.domainWithThreeNS.name,
- add=[],
- rem=[
- common.HostObjSet(
- hosts=[
- "ns1.my-nameserver-2.com",
- "ns1.cats-are-superior3.com",
- ]
- ),
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ with less_console_noise():
+ self.domainWithThreeNS.nameservers = [(self.nameserver1,)]
+ expectedCalls = [
+ call(
+ commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(commands.DeleteHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertFalse(self.domainWithThreeNS.is_active())
+ call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ call(commands.DeleteHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(
+ commands.UpdateDomain(
+ name=self.domainWithThreeNS.name,
+ add=[],
+ rem=[
+ common.HostObjSet(
+ hosts=[
+ "ns1.my-nameserver-2.com",
+ "ns1.cats-are-superior3.com",
+ ]
+ ),
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
+ call(commands.DeleteHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertFalse(self.domainWithThreeNS.is_active())
def test_user_replaces_nameservers(self):
"""
@@ -1403,59 +1355,58 @@ class TestRegistrantNameservers(MockEppLib):
And `commands.UpdateDomain` is sent to add #4 and #5 plus remove #2 and #3
And `commands.DeleteHost` is sent to delete #2 and #3
"""
- self.domainWithThreeNS.nameservers = [
- (self.nameserver1,),
- ("ns1.cats-are-superior1.com",),
- ("ns1.cats-are-superior2.com",),
- ]
-
- expectedCalls = [
- call(
- commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
- cleaned=True,
- ),
- call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- call(commands.DeleteHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(
- commands.CreateHost(name="ns1.cats-are-superior1.com", addrs=[]),
- cleaned=True,
- ),
- call(
- commands.CreateHost(name="ns1.cats-are-superior2.com", addrs=[]),
- cleaned=True,
- ),
- call(
- commands.UpdateDomain(
- name=self.domainWithThreeNS.name,
- add=[
- common.HostObjSet(
- hosts=[
- "ns1.cats-are-superior1.com",
- "ns1.cats-are-superior2.com",
- ]
- ),
- ],
- rem=[
- common.HostObjSet(
- hosts=[
- "ns1.my-nameserver-2.com",
- "ns1.cats-are-superior3.com",
- ]
- ),
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ with less_console_noise():
+ self.domainWithThreeNS.nameservers = [
+ (self.nameserver1,),
+ ("ns1.cats-are-superior1.com",),
+ ("ns1.cats-are-superior2.com",),
+ ]
+ expectedCalls = [
+ call(
+ commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertTrue(self.domainWithThreeNS.is_active())
+ call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ call(commands.DeleteHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(
+ commands.CreateHost(name="ns1.cats-are-superior1.com", addrs=[]),
+ cleaned=True,
+ ),
+ call(
+ commands.CreateHost(name="ns1.cats-are-superior2.com", addrs=[]),
+ cleaned=True,
+ ),
+ call(
+ commands.UpdateDomain(
+ name=self.domainWithThreeNS.name,
+ add=[
+ common.HostObjSet(
+ hosts=[
+ "ns1.cats-are-superior1.com",
+ "ns1.cats-are-superior2.com",
+ ]
+ ),
+ ],
+ rem=[
+ common.HostObjSet(
+ hosts=[
+ "ns1.my-nameserver-2.com",
+ "ns1.cats-are-superior3.com",
+ ]
+ ),
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertTrue(self.domainWithThreeNS.is_active())
def test_user_cannot_add_subordinate_without_ip(self):
"""
@@ -1465,11 +1416,10 @@ class TestRegistrantNameservers(MockEppLib):
with a subdomain of the domain and no IP addresses
Then Domain raises a user-friendly error
"""
-
- dotgovnameserver = "my-nameserver.gov"
-
- with self.assertRaises(NameserverError):
- self.domain.nameservers = [(dotgovnameserver,)]
+ with less_console_noise():
+ dotgovnameserver = "my-nameserver.gov"
+ with self.assertRaises(NameserverError):
+ self.domain.nameservers = [(dotgovnameserver,)]
def test_user_updates_ips(self):
"""
@@ -1480,46 +1430,45 @@ class TestRegistrantNameservers(MockEppLib):
with a different IP address(es)
Then `commands.UpdateHost` is sent to the registry
"""
- domain, _ = Domain.objects.get_or_create(name="nameserverwithip.gov", state=Domain.State.READY)
- domain.nameservers = [
- ("ns1.nameserverwithip.gov", ["2.3.4.5", "1.2.3.4"]),
- (
- "ns2.nameserverwithip.gov",
- ["1.2.3.4", "2.3.4.5", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"],
- ),
- ("ns3.nameserverwithip.gov", ["2.3.4.5"]),
- ]
-
- expectedCalls = [
- call(
- commands.InfoDomain(name="nameserverwithip.gov", auth_info=None),
- cleaned=True,
- ),
- call(commands.InfoHost(name="ns1.nameserverwithip.gov"), cleaned=True),
- call(commands.InfoHost(name="ns2.nameserverwithip.gov"), cleaned=True),
- call(commands.InfoHost(name="ns3.nameserverwithip.gov"), cleaned=True),
- call(
- commands.UpdateHost(
- name="ns2.nameserverwithip.gov",
- add=[common.Ip(addr="2001:0db8:85a3:0000:0000:8a2e:0370:7334", ip="v6")],
- rem=[],
- chg=None,
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="nameserverwithip.gov", state=Domain.State.READY)
+ domain.nameservers = [
+ ("ns1.nameserverwithip.gov", ["2.3.4.5", "1.2.3.4"]),
+ (
+ "ns2.nameserverwithip.gov",
+ ["1.2.3.4", "2.3.4.5", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"],
),
- cleaned=True,
- ),
- call(
- commands.UpdateHost(
- name="ns3.nameserverwithip.gov",
- add=[],
- rem=[common.Ip(addr="1.2.3.4", ip=None)],
- chg=None,
+ ("ns3.nameserverwithip.gov", ["2.3.4.5"]),
+ ]
+ expectedCalls = [
+ call(
+ commands.InfoDomain(name="nameserverwithip.gov", auth_info=None),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertTrue(domain.is_active())
+ call(commands.InfoHost(name="ns1.nameserverwithip.gov"), cleaned=True),
+ call(commands.InfoHost(name="ns2.nameserverwithip.gov"), cleaned=True),
+ call(commands.InfoHost(name="ns3.nameserverwithip.gov"), cleaned=True),
+ call(
+ commands.UpdateHost(
+ name="ns2.nameserverwithip.gov",
+ add=[common.Ip(addr="2001:0db8:85a3:0000:0000:8a2e:0370:7334", ip="v6")],
+ rem=[],
+ chg=None,
+ ),
+ cleaned=True,
+ ),
+ call(
+ commands.UpdateHost(
+ name="ns3.nameserverwithip.gov",
+ add=[],
+ rem=[common.Ip(addr="1.2.3.4", ip=None)],
+ chg=None,
+ ),
+ cleaned=True,
+ ),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertTrue(domain.is_active())
def test_user_cannot_add_non_subordinate_with_ip(self):
"""
@@ -1529,10 +1478,10 @@ class TestRegistrantNameservers(MockEppLib):
which is not a subdomain of the domain and has IP addresses
Then Domain raises a user-friendly error
"""
- dotgovnameserver = "mynameserverdotgov.gov"
-
- with self.assertRaises(NameserverError):
- self.domain.nameservers = [(dotgovnameserver, ["1.2.3"])]
+ with less_console_noise():
+ dotgovnameserver = "mynameserverdotgov.gov"
+ with self.assertRaises(NameserverError):
+ self.domain.nameservers = [(dotgovnameserver, ["1.2.3"])]
def test_nameservers_are_idempotent(self):
"""
@@ -1541,60 +1490,60 @@ class TestRegistrantNameservers(MockEppLib):
to the registry twice with identical data
Then no errors are raised in Domain
"""
-
- # Checking that it doesn't create or update even if out of order
- self.domainWithThreeNS.nameservers = [
- (self.nameserver3,),
- (self.nameserver1,),
- (self.nameserver2,),
- ]
-
- expectedCalls = [
- call(
- commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
- cleaned=True,
- ),
- call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
- call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
- ]
-
- self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
- self.assertEqual(self.mockedSendFunction.call_count, 4)
+ with less_console_noise():
+ # Checking that it doesn't create or update even if out of order
+ self.domainWithThreeNS.nameservers = [
+ (self.nameserver3,),
+ (self.nameserver1,),
+ (self.nameserver2,),
+ ]
+ expectedCalls = [
+ call(
+ commands.InfoDomain(name=self.domainWithThreeNS.name, auth_info=None),
+ cleaned=True,
+ ),
+ call(commands.InfoHost(name="ns1.my-nameserver-1.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.my-nameserver-2.com"), cleaned=True),
+ call(commands.InfoHost(name="ns1.cats-are-superior3.com"), cleaned=True),
+ ]
+ self.mockedSendFunction.assert_has_calls(expectedCalls, any_order=True)
+ self.assertEqual(self.mockedSendFunction.call_count, 4)
def test_is_subdomain_with_no_ip(self):
- domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
-
- with self.assertRaises(NameserverError):
- domain.nameservers = [
- ("ns1.nameserversubdomain.gov",),
- ("ns2.nameserversubdomain.gov",),
- ]
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
+ with self.assertRaises(NameserverError):
+ domain.nameservers = [
+ ("ns1.nameserversubdomain.gov",),
+ ("ns2.nameserversubdomain.gov",),
+ ]
def test_not_subdomain_but_has_ip(self):
- domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
-
- with self.assertRaises(NameserverError):
- domain.nameservers = [
- ("ns1.cats-da-best.gov", ["1.2.3.4"]),
- ("ns2.cats-da-best.gov", ["2.3.4.5"]),
- ]
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
+ with self.assertRaises(NameserverError):
+ domain.nameservers = [
+ ("ns1.cats-da-best.gov", ["1.2.3.4"]),
+ ("ns2.cats-da-best.gov", ["2.3.4.5"]),
+ ]
def test_is_subdomain_but_ip_addr_not_valid(self):
- domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="nameserversubdomain.gov", state=Domain.State.READY)
- with self.assertRaises(NameserverError):
- domain.nameservers = [
- ("ns1.nameserversubdomain.gov", ["1.2.3"]),
- ("ns2.nameserversubdomain.gov", ["2.3.4"]),
- ]
+ with self.assertRaises(NameserverError):
+ domain.nameservers = [
+ ("ns1.nameserversubdomain.gov", ["1.2.3"]),
+ ("ns2.nameserversubdomain.gov", ["2.3.4"]),
+ ]
def test_setting_not_allowed(self):
"""Scenario: A domain state is not Ready or DNS needed
then setting nameservers is not allowed"""
- domain, _ = Domain.objects.get_or_create(name="onholdDomain.gov", state=Domain.State.ON_HOLD)
- with self.assertRaises(ActionNotAllowed):
- domain.nameservers = [self.nameserver1, self.nameserver2]
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="onholdDomain.gov", state=Domain.State.ON_HOLD)
+ with self.assertRaises(ActionNotAllowed):
+ domain.nameservers = [self.nameserver1, self.nameserver2]
def test_nameserver_returns_on_registry_error(self):
"""
@@ -1602,28 +1551,25 @@ class TestRegistrantNameservers(MockEppLib):
Registry is unavailable and throws exception when attempting to build cache from
registry. Nameservers retrieved from database.
"""
- domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
- # set the host and host_ips directly in the database; this is normally handled through
- # fetch_cache
- host, _ = Host.objects.get_or_create(domain=domain, name="ns1.fake.gov")
- host_ip, _ = HostIP.objects.get_or_create(host=host, address="1.1.1.1")
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
+ # set the host and host_ips directly in the database; this is normally handled through
+ # fetch_cache
+ host, _ = Host.objects.get_or_create(domain=domain, name="ns1.fake.gov")
+ host_ip, _ = HostIP.objects.get_or_create(host=host, address="1.1.1.1")
- # mock that registry throws an error on the InfoHost send
+ # mock that registry throws an error on the InfoHost send
+ def side_effect(_request, cleaned):
+ raise RegistryError(code=ErrorCode.COMMAND_FAILED)
- def side_effect(_request, cleaned):
- raise RegistryError(code=ErrorCode.COMMAND_FAILED)
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- nameservers = domain.nameservers
-
- self.assertEqual(len(nameservers), 1)
- self.assertEqual(nameservers[0][0], "ns1.fake.gov")
- self.assertEqual(nameservers[0][1], ["1.1.1.1"])
-
- patcher.stop()
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ nameservers = domain.nameservers
+ self.assertEqual(len(nameservers), 1)
+ self.assertEqual(nameservers[0][0], "ns1.fake.gov")
+ self.assertEqual(nameservers[0][1], ["1.1.1.1"])
+ patcher.stop()
def test_nameservers_stored_on_fetch_cache(self):
"""
@@ -1633,24 +1579,23 @@ class TestRegistrantNameservers(MockEppLib):
of 'fake.host.com' from InfoDomain and an array of 2 IPs: 1.2.3.4 and 2.3.4.5
from InfoHost
"""
- domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
-
- # mock the get_or_create methods for Host and HostIP
- with patch.object(Host.objects, "get_or_create") as mock_host_get_or_create, patch.object(
- HostIP.objects, "get_or_create"
- ) as mock_host_ip_get_or_create:
- # Set the return value for the mocks
- mock_host_get_or_create.return_value = (Host(), True)
- mock_host_ip_get_or_create.return_value = (HostIP(), True)
-
- # force fetch_cache to be called, which will return above documented mocked hosts
- domain.nameservers
- # assert that the mocks are called
- mock_host_get_or_create.assert_called_once_with(domain=domain, name="fake.host.com")
- # Retrieve the mocked_host from the return value of the mock
- actual_mocked_host, _ = mock_host_get_or_create.return_value
- mock_host_ip_get_or_create.assert_called_with(address="2.3.4.5", host=actual_mocked_host)
- self.assertEqual(mock_host_ip_get_or_create.call_count, 2)
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
+ # mock the get_or_create methods for Host and HostIP
+ with patch.object(Host.objects, "get_or_create") as mock_host_get_or_create, patch.object(
+ HostIP.objects, "get_or_create"
+ ) as mock_host_ip_get_or_create:
+ # Set the return value for the mocks
+ mock_host_get_or_create.return_value = (Host(), True)
+ mock_host_ip_get_or_create.return_value = (HostIP(), True)
+ # force fetch_cache to be called, which will return above documented mocked hosts
+ domain.nameservers
+ # assert that the mocks are called
+ mock_host_get_or_create.assert_called_once_with(domain=domain, name="fake.host.com")
+ # Retrieve the mocked_host from the return value of the mock
+ actual_mocked_host, _ = mock_host_get_or_create.return_value
+ mock_host_ip_get_or_create.assert_called_with(address="2.3.4.5", host=actual_mocked_host)
+ self.assertEqual(mock_host_ip_get_or_create.call_count, 2)
@skip("not implemented yet")
def test_update_is_unsuccessful(self):
@@ -1791,54 +1736,51 @@ class TestRegistrantDNSSEC(MockEppLib):
else:
return MagicMock(res_data=[self.mockDataInfoHosts])
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- domain.dnssecdata = self.dnssecExtensionWithDsData
-
- # get the DNS SEC extension added to the UpdateDomain command and
- # verify that it is properly sent
- # args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
- # assert that the extension on the update matches
- self.assertEquals(
- args[0].extensions[0],
- self.createUpdateExtension(self.dnssecExtensionWithDsData),
- )
- # test that the dnssecdata getter is functioning properly
- dnssecdata_get = domain.dnssecdata
- mocked_send.assert_has_calls(
- [
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ with less_console_noise():
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ # get the DNS SEC extension added to the UpdateDomain command and
+ # verify that it is properly sent
+ # args[0] is the _request sent to registry
+ args, _ = mocked_send.call_args
+ # assert that the extension on the update matches
+ self.assertEquals(
+ args[0].extensions[0],
+ self.createUpdateExtension(self.dnssecExtensionWithDsData),
+ )
+ # test that the dnssecdata getter is functioning properly
+ dnssecdata_get = domain.dnssecdata
+ mocked_send.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.UpdateDomain(
- name="dnssec-dsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
- )
-
- self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
-
- patcher.stop()
+ ]
+ )
+ self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
+ patcher.stop()
def test_dnssec_is_idempotent(self):
"""
@@ -1872,54 +1814,51 @@ class TestRegistrantDNSSEC(MockEppLib):
else:
return MagicMock(res_data=[self.mockDataInfoHosts])
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
-
- # set the dnssecdata once
- domain.dnssecdata = self.dnssecExtensionWithDsData
- # set the dnssecdata again
- domain.dnssecdata = self.dnssecExtensionWithDsData
- # test that the dnssecdata getter is functioning properly
- dnssecdata_get = domain.dnssecdata
- mocked_send.assert_has_calls(
- [
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ with less_console_noise():
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ # set the dnssecdata once
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ # set the dnssecdata again
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ # test that the dnssecdata getter is functioning properly
+ dnssecdata_get = domain.dnssecdata
+ mocked_send.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.UpdateDomain(
- name="dnssec-dsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
- )
-
- self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
-
- patcher.stop()
+ ]
+ )
+ self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
+ patcher.stop()
def test_user_adds_dnssec_data_multiple_dsdata(self):
"""
@@ -1949,48 +1888,45 @@ class TestRegistrantDNSSEC(MockEppLib):
else:
return MagicMock(res_data=[self.mockDataInfoHosts])
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
-
- domain.dnssecdata = self.dnssecExtensionWithMultDsData
- # get the DNS SEC extension added to the UpdateDomain command
- # and verify that it is properly sent
- # args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
- # assert that the extension matches
- self.assertEquals(
- args[0].extensions[0],
- self.createUpdateExtension(self.dnssecExtensionWithMultDsData),
- )
- # test that the dnssecdata getter is functioning properly
- dnssecdata_get = domain.dnssecdata
- mocked_send.assert_has_calls(
- [
- call(
- commands.UpdateDomain(
- name="dnssec-multdsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ with less_console_noise():
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
+ domain.dnssecdata = self.dnssecExtensionWithMultDsData
+ # get the DNS SEC extension added to the UpdateDomain command
+ # and verify that it is properly sent
+ # args[0] is the _request sent to registry
+ args, _ = mocked_send.call_args
+ # assert that the extension matches
+ self.assertEquals(
+ args[0].extensions[0],
+ self.createUpdateExtension(self.dnssecExtensionWithMultDsData),
+ )
+ # test that the dnssecdata getter is functioning properly
+ dnssecdata_get = domain.dnssecdata
+ mocked_send.assert_has_calls(
+ [
+ call(
+ commands.UpdateDomain(
+ name="dnssec-multdsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.InfoDomain(
- name="dnssec-multdsdata.gov",
+ call(
+ commands.InfoDomain(
+ name="dnssec-multdsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
- )
-
- self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData.dsData)
-
- patcher.stop()
+ ]
+ )
+ self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData.dsData)
+ patcher.stop()
def test_user_removes_dnssec_data(self):
"""
@@ -2021,65 +1957,64 @@ class TestRegistrantDNSSEC(MockEppLib):
else:
return MagicMock(res_data=[self.mockDataInfoHosts])
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- # dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
- # domain._invalidate_cache()
- domain.dnssecdata = self.dnssecExtensionWithDsData
- domain.dnssecdata = self.dnssecExtensionRemovingDsData
- # get the DNS SEC extension added to the UpdateDomain command and
- # verify that it is properly sent
- # args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
- # assert that the extension on the update matches
- self.assertEquals(
- args[0].extensions[0],
- self.createUpdateExtension(
- self.dnssecExtensionWithDsData,
- remove=True,
- ),
- )
- mocked_send.assert_has_calls(
- [
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
- ),
- cleaned=True,
+ with less_console_noise():
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ # dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
+ # domain._invalidate_cache()
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionRemovingDsData
+ # get the DNS SEC extension added to the UpdateDomain command and
+ # verify that it is properly sent
+ # args[0] is the _request sent to registry
+ args, _ = mocked_send.call_args
+ # assert that the extension on the update matches
+ self.assertEquals(
+ args[0].extensions[0],
+ self.createUpdateExtension(
+ self.dnssecExtensionWithDsData,
+ remove=True,
),
- call(
- commands.UpdateDomain(
- name="dnssec-dsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ )
+ mocked_send.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.InfoDomain(
- name="dnssec-dsdata.gov",
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- call(
- commands.UpdateDomain(
- name="dnssec-dsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
),
- cleaned=True,
- ),
- ]
- )
-
- patcher.stop()
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
+ ]
+ )
+ patcher.stop()
def test_update_is_unsuccessful(self):
"""
@@ -2087,12 +2022,11 @@ class TestRegistrantDNSSEC(MockEppLib):
When an error is returned from epplibwrapper
Then a user-friendly error message is returned for displaying on the web
"""
-
- domain, _ = Domain.objects.get_or_create(name="dnssec-invalid.gov")
-
- with self.assertRaises(RegistryError) as err:
- domain.dnssecdata = self.dnssecExtensionWithDsData
- self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
+ with less_console_noise():
+ domain, _ = Domain.objects.get_or_create(name="dnssec-invalid.gov")
+ with self.assertRaises(RegistryError) as err:
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
class TestExpirationDate(MockEppLib):
@@ -2117,44 +2051,49 @@ class TestExpirationDate(MockEppLib):
def test_expiration_date_setter_not_implemented(self):
"""assert that the setter for expiration date is not implemented and will raise error"""
- with self.assertRaises(NotImplementedError):
- self.domain.registry_expiration_date = datetime.date.today()
+ with less_console_noise():
+ with self.assertRaises(NotImplementedError):
+ self.domain.registry_expiration_date = datetime.date.today()
def test_renew_domain(self):
"""assert that the renew_domain sets new expiration date in cache and saves to registrar"""
- self.domain.renew_domain()
- test_date = datetime.date(2023, 5, 25)
- self.assertEquals(self.domain._cache["ex_date"], test_date)
- self.assertEquals(self.domain.expiration_date, test_date)
+ with less_console_noise():
+ self.domain.renew_domain()
+ test_date = datetime.date(2023, 5, 25)
+ self.assertEquals(self.domain._cache["ex_date"], test_date)
+ self.assertEquals(self.domain.expiration_date, test_date)
def test_renew_domain_error(self):
"""assert that the renew_domain raises an exception when registry raises error"""
- with self.assertRaises(RegistryError):
- self.domain_w_error.renew_domain()
+ with less_console_noise():
+ with self.assertRaises(RegistryError):
+ self.domain_w_error.renew_domain()
def test_is_expired(self):
"""assert that is_expired returns true for expiration_date in past"""
- # force fetch_cache to be called
- self.domain.statuses
- self.assertTrue(self.domain.is_expired)
+ with less_console_noise():
+ # force fetch_cache to be called
+ self.domain.statuses
+ self.assertTrue(self.domain.is_expired)
def test_is_not_expired(self):
"""assert that is_expired returns false for expiration in future"""
- # to do this, need to mock value returned from timezone.now
- # set now to 2023-01-01
- mocked_datetime = datetime.datetime(2023, 1, 1, 12, 0, 0)
- # force fetch_cache which sets the expiration date to 2023-05-25
- self.domain.statuses
-
- with patch("registrar.models.domain.timezone.now", return_value=mocked_datetime):
- self.assertFalse(self.domain.is_expired())
+ with less_console_noise():
+ # to do this, need to mock value returned from timezone.now
+ # set now to 2023-01-01
+ mocked_datetime = datetime.datetime(2023, 1, 1, 12, 0, 0)
+ # force fetch_cache which sets the expiration date to 2023-05-25
+ self.domain.statuses
+ with patch("registrar.models.domain.timezone.now", return_value=mocked_datetime):
+ self.assertFalse(self.domain.is_expired())
def test_expiration_date_updated_on_info_domain_call(self):
"""assert that expiration date in db is updated on info domain call"""
- # force fetch_cache to be called
- self.domain.statuses
- test_date = datetime.date(2023, 5, 25)
- self.assertEquals(self.domain.expiration_date, test_date)
+ with less_console_noise():
+ # force fetch_cache to be called
+ self.domain.statuses
+ test_date = datetime.date(2023, 5, 25)
+ self.assertEquals(self.domain.expiration_date, test_date)
class TestCreationDate(MockEppLib):
@@ -2169,7 +2108,7 @@ class TestCreationDate(MockEppLib):
self.domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
# creation_date returned from mockDataInfoDomain with creation date:
# cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35)
- self.creation_date = datetime.datetime(2023, 5, 25, 19, 45, 35)
+ self.creation_date = make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35))
def tearDown(self):
Domain.objects.all().delete()
@@ -2212,29 +2151,30 @@ class TestAnalystClientHold(MockEppLib):
When `domain.place_client_hold()` is called
Then `CLIENT_HOLD` is added to the domain's statuses
"""
- self.domain.place_client_hold()
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.UpdateDomain(
- name="fake.gov",
- add=[
- common.Status(
- state=Domain.Status.CLIENT_HOLD,
- description="",
- lang="en",
- )
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
- ),
- cleaned=True,
- )
- ]
- )
- self.assertEquals(self.domain.state, Domain.State.ON_HOLD)
+ with less_console_noise():
+ self.domain.place_client_hold()
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.UpdateDomain(
+ name="fake.gov",
+ add=[
+ common.Status(
+ state=Domain.Status.CLIENT_HOLD,
+ description="",
+ lang="en",
+ )
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ )
+ ]
+ )
+ self.assertEquals(self.domain.state, Domain.State.ON_HOLD)
def test_analyst_places_client_hold_idempotent(self):
"""
@@ -2243,29 +2183,30 @@ class TestAnalystClientHold(MockEppLib):
When `domain.place_client_hold()` is called
Then Domain returns normally (without error)
"""
- self.domain_on_hold.place_client_hold()
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.UpdateDomain(
- name="fake-on-hold.gov",
- add=[
- common.Status(
- state=Domain.Status.CLIENT_HOLD,
- description="",
- lang="en",
- )
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
- ),
- cleaned=True,
- )
- ]
- )
- self.assertEquals(self.domain_on_hold.state, Domain.State.ON_HOLD)
+ with less_console_noise():
+ self.domain_on_hold.place_client_hold()
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.UpdateDomain(
+ name="fake-on-hold.gov",
+ add=[
+ common.Status(
+ state=Domain.Status.CLIENT_HOLD,
+ description="",
+ lang="en",
+ )
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ )
+ ]
+ )
+ self.assertEquals(self.domain_on_hold.state, Domain.State.ON_HOLD)
def test_analyst_removes_client_hold(self):
"""
@@ -2274,29 +2215,30 @@ class TestAnalystClientHold(MockEppLib):
When `domain.remove_client_hold()` is called
Then `CLIENT_HOLD` is no longer in the domain's statuses
"""
- self.domain_on_hold.revert_client_hold()
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.UpdateDomain(
- name="fake-on-hold.gov",
- rem=[
- common.Status(
- state=Domain.Status.CLIENT_HOLD,
- description="",
- lang="en",
- )
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
- ),
- cleaned=True,
- )
- ]
- )
- self.assertEquals(self.domain_on_hold.state, Domain.State.READY)
+ with less_console_noise():
+ self.domain_on_hold.revert_client_hold()
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.UpdateDomain(
+ name="fake-on-hold.gov",
+ rem=[
+ common.Status(
+ state=Domain.Status.CLIENT_HOLD,
+ description="",
+ lang="en",
+ )
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ )
+ ]
+ )
+ self.assertEquals(self.domain_on_hold.state, Domain.State.READY)
def test_analyst_removes_client_hold_idempotent(self):
"""
@@ -2305,29 +2247,30 @@ class TestAnalystClientHold(MockEppLib):
When `domain.remove_client_hold()` is called
Then Domain returns normally (without error)
"""
- self.domain.revert_client_hold()
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.UpdateDomain(
- name="fake.gov",
- rem=[
- common.Status(
- state=Domain.Status.CLIENT_HOLD,
- description="",
- lang="en",
- )
- ],
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
- ),
- cleaned=True,
- )
- ]
- )
- self.assertEquals(self.domain.state, Domain.State.READY)
+ with less_console_noise():
+ self.domain.revert_client_hold()
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.UpdateDomain(
+ name="fake.gov",
+ rem=[
+ common.Status(
+ state=Domain.Status.CLIENT_HOLD,
+ description="",
+ lang="en",
+ )
+ ],
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ )
+ ]
+ )
+ self.assertEquals(self.domain.state, Domain.State.READY)
def test_update_is_unsuccessful(self):
"""
@@ -2339,18 +2282,17 @@ class TestAnalystClientHold(MockEppLib):
def side_effect(_request, cleaned):
raise RegistryError(code=ErrorCode.OBJECT_STATUS_PROHIBITS_OPERATION)
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- # if RegistryError is raised, admin formats user-friendly
- # error message if error is_client_error, is_session_error, or
- # is_server_error; so test for those conditions
- with self.assertRaises(RegistryError) as err:
- self.domain.place_client_hold()
- self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
-
- patcher.stop()
+ with less_console_noise():
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+ # if RegistryError is raised, admin formats user-friendly
+ # error message if error is_client_error, is_session_error, or
+ # is_server_error; so test for those conditions
+ with self.assertRaises(RegistryError) as err:
+ self.domain.place_client_hold()
+ self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
+ patcher.stop()
class TestAnalystLock(TestCase):
@@ -2443,31 +2385,28 @@ class TestAnalystDelete(MockEppLib):
The deleted date is set.
"""
- # Put the domain in client hold
- self.domain.place_client_hold()
- # Delete it...
- self.domain.deletedInEpp()
- self.domain.save()
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.DeleteDomain(name="fake.gov"),
- cleaned=True,
- )
- ]
- )
-
- # Domain itself should not be deleted
- self.assertNotEqual(self.domain, None)
-
- # Domain should have the right state
- self.assertEqual(self.domain.state, Domain.State.DELETED)
-
- # Domain should have a deleted
- self.assertNotEqual(self.domain.deleted, None)
-
- # Cache should be invalidated
- self.assertEqual(self.domain._cache, {})
+ with less_console_noise():
+ # Put the domain in client hold
+ self.domain.place_client_hold()
+ # Delete it...
+ self.domain.deletedInEpp()
+ self.domain.save()
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.DeleteDomain(name="fake.gov"),
+ cleaned=True,
+ )
+ ]
+ )
+ # Domain itself should not be deleted
+ self.assertNotEqual(self.domain, None)
+ # Domain should have the right state
+ self.assertEqual(self.domain.state, Domain.State.DELETED)
+ # Domain should have a deleted
+ self.assertNotEqual(self.domain.deleted, None)
+ # Cache should be invalidated
+ self.assertEqual(self.domain._cache, {})
def test_deletion_is_unsuccessful(self):
"""
@@ -2476,29 +2415,28 @@ class TestAnalystDelete(MockEppLib):
Then a client error is returned of code 2305
And `state` is not set to `DELETED`
"""
- # Desired domain
- domain, _ = Domain.objects.get_or_create(name="failDelete.gov", state=Domain.State.ON_HOLD)
- # Put the domain in client hold
- domain.place_client_hold()
-
- # Delete it
- with self.assertRaises(RegistryError) as err:
- domain.deletedInEpp()
- domain.save()
- self.assertTrue(err.is_client_error() and err.code == ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION)
- self.mockedSendFunction.assert_has_calls(
- [
- call(
- commands.DeleteDomain(name="failDelete.gov"),
- cleaned=True,
- )
- ]
- )
-
- # Domain itself should not be deleted
- self.assertNotEqual(domain, None)
- # State should not have changed
- self.assertEqual(domain.state, Domain.State.ON_HOLD)
+ with less_console_noise():
+ # Desired domain
+ domain, _ = Domain.objects.get_or_create(name="failDelete.gov", state=Domain.State.ON_HOLD)
+ # Put the domain in client hold
+ domain.place_client_hold()
+ # Delete it
+ with self.assertRaises(RegistryError) as err:
+ domain.deletedInEpp()
+ domain.save()
+ self.assertTrue(err.is_client_error() and err.code == ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION)
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.DeleteDomain(name="failDelete.gov"),
+ cleaned=True,
+ )
+ ]
+ )
+ # Domain itself should not be deleted
+ self.assertNotEqual(domain, None)
+ # State should not have changed
+ self.assertEqual(domain.state, Domain.State.ON_HOLD)
def test_deletion_ready_fsm_failure(self):
"""
@@ -2511,15 +2449,15 @@ class TestAnalystDelete(MockEppLib):
The deleted date is still null.
"""
- self.assertEqual(self.domain.state, Domain.State.READY)
- with self.assertRaises(TransitionNotAllowed) as err:
- self.domain.deletedInEpp()
- self.domain.save()
- self.assertTrue(err.is_client_error() and err.code == ErrorCode.OBJECT_STATUS_PROHIBITS_OPERATION)
- # Domain should not be deleted
- self.assertNotEqual(self.domain, None)
- # Domain should have the right state
- self.assertEqual(self.domain.state, Domain.State.READY)
-
- # deleted should be null
- self.assertEqual(self.domain.deleted, None)
+ with less_console_noise():
+ self.assertEqual(self.domain.state, Domain.State.READY)
+ with self.assertRaises(TransitionNotAllowed) as err:
+ self.domain.deletedInEpp()
+ self.domain.save()
+ self.assertTrue(err.is_client_error() and err.code == ErrorCode.OBJECT_STATUS_PROHIBITS_OPERATION)
+ # Domain should not be deleted
+ self.assertNotEqual(self.domain, None)
+ # Domain should have the right state
+ self.assertEqual(self.domain.state, Domain.State.READY)
+ # deleted should be null
+ self.assertEqual(self.domain.deleted, None)
diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py
index a85fb5849..630904218 100644
--- a/src/registrar/tests/test_reports.py
+++ b/src/registrar/tests/test_reports.py
@@ -23,6 +23,7 @@ import boto3_mocking
from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore
from datetime import date, datetime, timedelta
from django.utils import timezone
+from .common import less_console_noise
class CsvReportsTest(TestCase):
@@ -80,41 +81,43 @@ class CsvReportsTest(TestCase):
@boto3_mocking.patching
def test_generate_federal_report(self):
"""Ensures that we correctly generate current-federal.csv"""
- mock_client = MagicMock()
- fake_open = mock_open()
- expected_file_content = [
- call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
- call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
- call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
- ]
- # We don't actually want to write anything for a test case,
- # we just want to verify what is being written.
- with boto3_mocking.clients.handler_for("s3", mock_client):
- with patch("builtins.open", fake_open):
- call_command("generate_current_federal_report", checkpath=False)
- content = fake_open()
+ with less_console_noise():
+ mock_client = MagicMock()
+ fake_open = mock_open()
+ expected_file_content = [
+ call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
+ call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
+ call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
+ ]
+ # We don't actually want to write anything for a test case,
+ # we just want to verify what is being written.
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ with patch("builtins.open", fake_open):
+ call_command("generate_current_federal_report", checkpath=False)
+ content = fake_open()
- content.write.assert_has_calls(expected_file_content)
+ content.write.assert_has_calls(expected_file_content)
@boto3_mocking.patching
def test_generate_full_report(self):
"""Ensures that we correctly generate current-full.csv"""
- mock_client = MagicMock()
- fake_open = mock_open()
- expected_file_content = [
- call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
- call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
- call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
- call("adomain2.gov,Interstate,,,,, \r\n"),
- ]
- # We don't actually want to write anything for a test case,
- # we just want to verify what is being written.
- with boto3_mocking.clients.handler_for("s3", mock_client):
- with patch("builtins.open", fake_open):
- call_command("generate_current_full_report", checkpath=False)
- content = fake_open()
+ with less_console_noise():
+ mock_client = MagicMock()
+ fake_open = mock_open()
+ expected_file_content = [
+ call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
+ call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
+ call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
+ call("adomain2.gov,Interstate,,,,, \r\n"),
+ ]
+ # We don't actually want to write anything for a test case,
+ # we just want to verify what is being written.
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ with patch("builtins.open", fake_open):
+ call_command("generate_current_full_report", checkpath=False)
+ content = fake_open()
- content.write.assert_has_calls(expected_file_content)
+ content.write.assert_has_calls(expected_file_content)
@boto3_mocking.patching
def test_not_found_full_report(self):
@@ -123,19 +126,20 @@ class CsvReportsTest(TestCase):
def side_effect(Bucket, Key):
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
- mock_client = MagicMock()
- mock_client.get_object.side_effect = side_effect
+ with less_console_noise():
+ mock_client = MagicMock()
+ mock_client.get_object.side_effect = side_effect
- response = None
- with boto3_mocking.clients.handler_for("s3", mock_client):
- with patch("boto3.client", return_value=mock_client):
- with self.assertRaises(S3ClientError) as context:
- response = self.client.get("/api/v1/get-report/current-full")
- # Check that the response has status code 500
- self.assertEqual(response.status_code, 500)
+ response = None
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ with patch("boto3.client", return_value=mock_client):
+ with self.assertRaises(S3ClientError) as context:
+ response = self.client.get("/api/v1/get-report/current-full")
+ # Check that the response has status code 500
+ self.assertEqual(response.status_code, 500)
- # Check that we get the right error back from the page
- self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
+ # Check that we get the right error back from the page
+ self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
@boto3_mocking.patching
def test_not_found_federal_report(self):
@@ -144,83 +148,86 @@ class CsvReportsTest(TestCase):
def side_effect(Bucket, Key):
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
- mock_client = MagicMock()
- mock_client.get_object.side_effect = side_effect
+ with less_console_noise():
+ mock_client = MagicMock()
+ mock_client.get_object.side_effect = side_effect
- with boto3_mocking.clients.handler_for("s3", mock_client):
- with patch("boto3.client", return_value=mock_client):
- with self.assertRaises(S3ClientError) as context:
- response = self.client.get("/api/v1/get-report/current-federal")
- # Check that the response has status code 500
- self.assertEqual(response.status_code, 500)
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ with patch("boto3.client", return_value=mock_client):
+ with self.assertRaises(S3ClientError) as context:
+ response = self.client.get("/api/v1/get-report/current-federal")
+ # Check that the response has status code 500
+ self.assertEqual(response.status_code, 500)
- # Check that we get the right error back from the page
- self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
+ # Check that we get the right error back from the page
+ self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
@boto3_mocking.patching
def test_load_federal_report(self):
"""Tests the get_current_federal api endpoint"""
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
+ with less_console_noise():
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
- with open("registrar/tests/data/fake_current_federal.csv", "r") as file:
- file_content = file.read()
+ with open("registrar/tests/data/fake_current_federal.csv", "r") as file:
+ file_content = file.read()
- # Mock a recieved file
- mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
- with boto3_mocking.clients.handler_for("s3", mock_client):
- request = self.factory.get("/fake-path")
- response = get_current_federal(request)
+ # Mock a recieved file
+ mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ request = self.factory.get("/fake-path")
+ response = get_current_federal(request)
- # Check that we are sending the correct calls.
- # Ensures that we are decoding the file content recieved from AWS.
- expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-federal.csv")]
- mock_client_instance.assert_has_calls(expected_call)
+ # Check that we are sending the correct calls.
+ # Ensures that we are decoding the file content recieved from AWS.
+ expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-federal.csv")]
+ mock_client_instance.assert_has_calls(expected_call)
- # Check that the response has status code 200
- self.assertEqual(response.status_code, 200)
+ # Check that the response has status code 200
+ self.assertEqual(response.status_code, 200)
- # Check that the response contains what we expect
- expected_file_content = (
- "Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
- "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
- "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,"
- ).encode()
+ # Check that the response contains what we expect
+ expected_file_content = (
+ "Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
+ "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
+ "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,"
+ ).encode()
- self.assertEqual(expected_file_content, response.content)
+ self.assertEqual(expected_file_content, response.content)
@boto3_mocking.patching
def test_load_full_report(self):
"""Tests the current-federal api link"""
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
+ with less_console_noise():
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
- with open("registrar/tests/data/fake_current_full.csv", "r") as file:
- file_content = file.read()
+ with open("registrar/tests/data/fake_current_full.csv", "r") as file:
+ file_content = file.read()
- # Mock a recieved file
- mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
- with boto3_mocking.clients.handler_for("s3", mock_client):
- request = self.factory.get("/fake-path")
- response = get_current_full(request)
+ # Mock a recieved file
+ mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
+ with boto3_mocking.clients.handler_for("s3", mock_client):
+ request = self.factory.get("/fake-path")
+ response = get_current_full(request)
- # Check that we are sending the correct calls.
- # Ensures that we are decoding the file content recieved from AWS.
- expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-full.csv")]
- mock_client_instance.assert_has_calls(expected_call)
+ # Check that we are sending the correct calls.
+ # Ensures that we are decoding the file content recieved from AWS.
+ expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-full.csv")]
+ mock_client_instance.assert_has_calls(expected_call)
- # Check that the response has status code 200
- self.assertEqual(response.status_code, 200)
+ # Check that the response has status code 200
+ self.assertEqual(response.status_code, 200)
- # Check that the response contains what we expect
- expected_file_content = (
- "Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
- "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
- "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n"
- "adomain2.gov,Interstate,,,,,"
- ).encode()
+ # Check that the response contains what we expect
+ expected_file_content = (
+ "Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
+ "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
+ "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n"
+ "adomain2.gov,Interstate,,,,,"
+ ).encode()
- self.assertEqual(expected_file_content, response.content)
+ self.assertEqual(expected_file_content, response.content)
class ExportDataTest(MockEppLib):
@@ -339,192 +346,170 @@ class ExportDataTest(MockEppLib):
def test_export_domains_to_writer_security_emails(self):
"""Test that export_domains_to_writer returns the
expected security email"""
-
- # Add security email information
- self.domain_1.name = "defaultsecurity.gov"
- self.domain_1.save()
-
- # Invoke setter
- self.domain_1.security_contact
-
- # Invoke setter
- self.domain_2.security_contact
-
- # Invoke setter
- self.domain_3.security_contact
-
- # Create a CSV file in memory
- csv_file = StringIO()
- writer = csv.writer(csv_file)
-
- # Define columns, sort fields, and filter condition
- columns = [
- "Domain name",
- "Domain type",
- "Agency",
- "Organization name",
- "City",
- "State",
- "AO",
- "AO email",
- "Security contact email",
- "Status",
- "Expiration date",
- ]
- sort_fields = ["domain__name"]
- filter_condition = {
- "domain__state__in": [
- Domain.State.READY,
- Domain.State.DNS_NEEDED,
- Domain.State.ON_HOLD,
- ],
- }
-
- self.maxDiff = None
- # Call the export functions
- write_header(writer, columns)
- write_body(writer, columns, sort_fields, filter_condition)
-
- # Reset the CSV file's position to the beginning
- csv_file.seek(0)
-
- # Read the content into a variable
- csv_content = csv_file.read()
-
- # We expect READY domains,
- # sorted alphabetially by domain name
- expected_content = (
- "Domain name,Domain type,Agency,Organization name,City,State,AO,"
- "AO email,Security contact email,Status,Expiration date\n"
- "adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
- "adomain2.gov,Interstate,(blank),Dns needed\n"
- "ddomain3.gov,Federal,Armed Forces Retirement Home,123@mail.gov,On hold,2023-05-25\n"
- "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready"
- )
-
- # Normalize line endings and remove commas,
- # spaces and leading/trailing whitespace
- csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
- expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
-
- self.assertEqual(csv_content, expected_content)
+ with less_console_noise():
+ # Add security email information
+ self.domain_1.name = "defaultsecurity.gov"
+ self.domain_1.save()
+ # Invoke setter
+ self.domain_1.security_contact
+ # Invoke setter
+ self.domain_2.security_contact
+ # Invoke setter
+ self.domain_3.security_contact
+ # Create a CSV file in memory
+ csv_file = StringIO()
+ writer = csv.writer(csv_file)
+ # Define columns, sort fields, and filter condition
+ columns = [
+ "Domain name",
+ "Domain type",
+ "Agency",
+ "Organization name",
+ "City",
+ "State",
+ "AO",
+ "AO email",
+ "Security contact email",
+ "Status",
+ "Expiration date",
+ ]
+ sort_fields = ["domain__name"]
+ filter_condition = {
+ "domain__state__in": [
+ Domain.State.READY,
+ Domain.State.DNS_NEEDED,
+ Domain.State.ON_HOLD,
+ ],
+ }
+ self.maxDiff = None
+ # Call the export functions
+ write_header(writer, columns)
+ write_body(writer, columns, sort_fields, filter_condition)
+ # Reset the CSV file's position to the beginning
+ csv_file.seek(0)
+ # Read the content into a variable
+ csv_content = csv_file.read()
+ # We expect READY domains,
+ # sorted alphabetially by domain name
+ expected_content = (
+ "Domain name,Domain type,Agency,Organization name,City,State,AO,"
+ "AO email,Security contact email,Status,Expiration date\n"
+ "adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
+ "adomain2.gov,Interstate,(blank),Dns needed\n"
+ "ddomain3.gov,Federal,Armed Forces Retirement Home,123@mail.gov,On hold,2023-05-25\n"
+ "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready"
+ )
+ # Normalize line endings and remove commas,
+ # spaces and leading/trailing whitespace
+ csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
+ expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
+ self.assertEqual(csv_content, expected_content)
def test_write_body(self):
"""Test that write_body returns the
existing domain, test that sort by domain name works,
test that filter works"""
- # Create a CSV file in memory
- csv_file = StringIO()
- writer = csv.writer(csv_file)
+ with less_console_noise():
+ # Create a CSV file in memory
+ csv_file = StringIO()
+ writer = csv.writer(csv_file)
- # Define columns, sort fields, and filter condition
- columns = [
- "Domain name",
- "Domain type",
- "Agency",
- "Organization name",
- "City",
- "State",
- "AO",
- "AO email",
- "Submitter",
- "Submitter title",
- "Submitter email",
- "Submitter phone",
- "Security contact email",
- "Status",
- ]
- sort_fields = ["domain__name"]
- filter_condition = {
- "domain__state__in": [
- Domain.State.READY,
- Domain.State.DNS_NEEDED,
- Domain.State.ON_HOLD,
- ],
- }
-
- # Call the export functions
- write_header(writer, columns)
- write_body(writer, columns, sort_fields, filter_condition)
-
- # Reset the CSV file's position to the beginning
- csv_file.seek(0)
-
- # Read the content into a variable
- csv_content = csv_file.read()
-
- # We expect READY domains,
- # sorted alphabetially by domain name
- expected_content = (
- "Domain name,Domain type,Agency,Organization name,City,State,AO,"
- "AO email,Submitter,Submitter title,Submitter email,Submitter phone,"
- "Security contact email,Status\n"
- "adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
- "adomain2.gov,Interstate,Dns needed\n"
- "cdomain1.gov,Federal - Executive,World War I Centennial Commission,Ready\n"
- "ddomain3.gov,Federal,Armed Forces Retirement Home,On hold\n"
- )
-
- # Normalize line endings and remove commas,
- # spaces and leading/trailing whitespace
- csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
- expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
-
- self.assertEqual(csv_content, expected_content)
+ # Define columns, sort fields, and filter condition
+ columns = [
+ "Domain name",
+ "Domain type",
+ "Agency",
+ "Organization name",
+ "City",
+ "State",
+ "AO",
+ "AO email",
+ "Submitter",
+ "Submitter title",
+ "Submitter email",
+ "Submitter phone",
+ "Security contact email",
+ "Status",
+ ]
+ sort_fields = ["domain__name"]
+ filter_condition = {
+ "domain__state__in": [
+ Domain.State.READY,
+ Domain.State.DNS_NEEDED,
+ Domain.State.ON_HOLD,
+ ],
+ }
+ # Call the export functions
+ write_header(writer, columns)
+ write_body(writer, columns, sort_fields, filter_condition)
+ # Reset the CSV file's position to the beginning
+ csv_file.seek(0)
+ # Read the content into a variable
+ csv_content = csv_file.read()
+ # We expect READY domains,
+ # sorted alphabetially by domain name
+ expected_content = (
+ "Domain name,Domain type,Agency,Organization name,City,State,AO,"
+ "AO email,Submitter,Submitter title,Submitter email,Submitter phone,"
+ "Security contact email,Status\n"
+ "adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
+ "adomain2.gov,Interstate,Dns needed\n"
+ "cdomain1.gov,Federal - Executive,World War I Centennial Commission,Ready\n"
+ "ddomain3.gov,Federal,Armed Forces Retirement Home,On hold\n"
+ )
+ # Normalize line endings and remove commas,
+ # spaces and leading/trailing whitespace
+ csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
+ expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
+ self.assertEqual(csv_content, expected_content)
def test_write_body_additional(self):
"""An additional test for filters and multi-column sort"""
- # Create a CSV file in memory
- csv_file = StringIO()
- writer = csv.writer(csv_file)
-
- # Define columns, sort fields, and filter condition
- columns = [
- "Domain name",
- "Domain type",
- "Agency",
- "Organization name",
- "City",
- "State",
- "Security contact email",
- ]
- sort_fields = ["domain__name", "federal_agency", "organization_type"]
- filter_condition = {
- "organization_type__icontains": "federal",
- "domain__state__in": [
- Domain.State.READY,
- Domain.State.DNS_NEEDED,
- Domain.State.ON_HOLD,
- ],
- }
-
- # Call the export functions
- write_header(writer, columns)
- write_body(writer, columns, sort_fields, filter_condition)
-
- # Reset the CSV file's position to the beginning
- csv_file.seek(0)
-
- # Read the content into a variable
- csv_content = csv_file.read()
-
- # We expect READY domains,
- # federal only
- # sorted alphabetially by domain name
- expected_content = (
- "Domain name,Domain type,Agency,Organization name,City,"
- "State,Security contact email\n"
- "adomain10.gov,Federal,Armed Forces Retirement Home\n"
- "cdomain1.gov,Federal - Executive,World War I Centennial Commission\n"
- "ddomain3.gov,Federal,Armed Forces Retirement Home\n"
- )
-
- # Normalize line endings and remove commas,
- # spaces and leading/trailing whitespace
- csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
- expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
-
- self.assertEqual(csv_content, expected_content)
+ with less_console_noise():
+ # Create a CSV file in memory
+ csv_file = StringIO()
+ writer = csv.writer(csv_file)
+ # Define columns, sort fields, and filter condition
+ columns = [
+ "Domain name",
+ "Domain type",
+ "Agency",
+ "Organization name",
+ "City",
+ "State",
+ "Security contact email",
+ ]
+ sort_fields = ["domain__name", "federal_agency", "organization_type"]
+ filter_condition = {
+ "organization_type__icontains": "federal",
+ "domain__state__in": [
+ Domain.State.READY,
+ Domain.State.DNS_NEEDED,
+ Domain.State.ON_HOLD,
+ ],
+ }
+ # Call the export functions
+ write_header(writer, columns)
+ write_body(writer, columns, sort_fields, filter_condition)
+ # Reset the CSV file's position to the beginning
+ csv_file.seek(0)
+ # Read the content into a variable
+ csv_content = csv_file.read()
+ # We expect READY domains,
+ # federal only
+ # sorted alphabetially by domain name
+ expected_content = (
+ "Domain name,Domain type,Agency,Organization name,City,"
+ "State,Security contact email\n"
+ "adomain10.gov,Federal,Armed Forces Retirement Home\n"
+ "cdomain1.gov,Federal - Executive,World War I Centennial Commission\n"
+ "ddomain3.gov,Federal,Armed Forces Retirement Home\n"
+ )
+ # Normalize line endings and remove commas,
+ # spaces and leading/trailing whitespace
+ csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
+ expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
+ self.assertEqual(csv_content, expected_content)
def test_write_body_with_date_filter_pulls_domains_in_range(self):
"""Test that domains that are
@@ -538,88 +523,88 @@ class ExportDataTest(MockEppLib):
which are hard to mock.
TODO: Simplify is created_at is not needed for the report."""
+ with less_console_noise():
+ # Create a CSV file in memory
+ csv_file = StringIO()
+ writer = csv.writer(csv_file)
+ # We use timezone.make_aware to sync to server time a datetime object with the current date
+ # (using date.today()) and a specific time (using datetime.min.time()).
+ end_date = timezone.make_aware(datetime.combine(date.today() + timedelta(days=2), datetime.min.time()))
+ start_date = timezone.make_aware(datetime.combine(date.today() - timedelta(days=2), datetime.min.time()))
- # Create a CSV file in memory
- csv_file = StringIO()
- writer = csv.writer(csv_file)
- # We use timezone.make_aware to sync to server time a datetime object with the current date (using date.today())
- # and a specific time (using datetime.min.time()).
- end_date = timezone.make_aware(datetime.combine(date.today() + timedelta(days=2), datetime.min.time()))
- start_date = timezone.make_aware(datetime.combine(date.today() - timedelta(days=2), datetime.min.time()))
+ # Define columns, sort fields, and filter condition
+ columns = [
+ "Domain name",
+ "Domain type",
+ "Agency",
+ "Organization name",
+ "City",
+ "State",
+ "Status",
+ "Expiration date",
+ ]
+ sort_fields = [
+ "created_at",
+ "domain__name",
+ ]
+ sort_fields_for_deleted_domains = [
+ "domain__deleted",
+ "domain__name",
+ ]
+ filter_condition = {
+ "domain__state__in": [
+ Domain.State.READY,
+ ],
+ "domain__first_ready__lte": end_date,
+ "domain__first_ready__gte": start_date,
+ }
+ filter_conditions_for_deleted_domains = {
+ "domain__state__in": [
+ Domain.State.DELETED,
+ ],
+ "domain__deleted__lte": end_date,
+ "domain__deleted__gte": start_date,
+ }
- # Define columns, sort fields, and filter condition
- columns = [
- "Domain name",
- "Domain type",
- "Agency",
- "Organization name",
- "City",
- "State",
- "Status",
- "Expiration date",
- ]
- sort_fields = [
- "created_at",
- "domain__name",
- ]
- sort_fields_for_deleted_domains = [
- "domain__deleted",
- "domain__name",
- ]
- filter_condition = {
- "domain__state__in": [
- Domain.State.READY,
- ],
- "domain__first_ready__lte": end_date,
- "domain__first_ready__gte": start_date,
- }
- filter_conditions_for_deleted_domains = {
- "domain__state__in": [
- Domain.State.DELETED,
- ],
- "domain__deleted__lte": end_date,
- "domain__deleted__gte": start_date,
- }
+ # Call the export functions
+ write_header(writer, columns)
+ write_body(
+ writer,
+ columns,
+ sort_fields,
+ filter_condition,
+ )
+ write_body(
+ writer,
+ columns,
+ sort_fields_for_deleted_domains,
+ filter_conditions_for_deleted_domains,
+ )
- # Call the export functions
- write_header(writer, columns)
- write_body(
- writer,
- columns,
- sort_fields,
- filter_condition,
- )
- write_body(
- writer,
- columns,
- sort_fields_for_deleted_domains,
- filter_conditions_for_deleted_domains,
- )
+ # Reset the CSV file's position to the beginning
+ csv_file.seek(0)
- # Reset the CSV file's position to the beginning
- csv_file.seek(0)
+ # Read the content into a variable
+ csv_content = csv_file.read()
- # Read the content into a variable
- csv_content = csv_file.read()
+ # We expect READY domains first, created between today-2 and today+2, sorted by created_at then name
+ # and DELETED domains deleted between today-2 and today+2, sorted by deleted then name
+ expected_content = (
+ "Domain name,Domain type,Agency,Organization name,City,"
+ "State,Status,Expiration date\n"
+ "cdomain1.gov,Federal-Executive,World War I Centennial Commission,,,,Ready,\n"
+ "adomain10.gov,Federal,Armed Forces Retirement Home,,,,Ready,\n"
+ "zdomain9.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
+ "sdomain8.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
+ "xdomain7.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
+ )
- # We expect READY domains first, created between today-2 and today+2, sorted by created_at then name
- # and DELETED domains deleted between today-2 and today+2, sorted by deleted then name
- expected_content = (
- "Domain name,Domain type,Agency,Organization name,City,"
- "State,Status,Expiration date\n"
- "cdomain1.gov,Federal-Executive,World War I Centennial Commission,,,,Ready,\n"
- "adomain10.gov,Federal,Armed Forces Retirement Home,,,,Ready,\n"
- "zdomain9.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
- "sdomain8.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
- "xdomain7.gov,Federal,Armed Forces Retirement Home,,,,Deleted,\n"
- )
+ # Normalize line endings and remove commas,
+ # spaces and leading/trailing whitespace
+ csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
+ expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
- # Normalize line endings and remove commas,
- # spaces and leading/trailing whitespace
- csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
- expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
-
- self.assertEqual(csv_content, expected_content)
+ self.assertEqual(csv_content, expected_content)
class HelperFunctions(TestCase):
diff --git a/src/registrar/tests/test_transition_domain_migrations.py b/src/registrar/tests/test_transition_domain_migrations.py
index be4619e0b..e9453bd03 100644
--- a/src/registrar/tests/test_transition_domain_migrations.py
+++ b/src/registrar/tests/test_transition_domain_migrations.py
@@ -20,6 +20,9 @@ from registrar.models.contact import Contact
from .common import MockSESClient, less_console_noise
import boto3_mocking # type: ignore
+import logging
+
+logger = logging.getLogger(__name__)
class TestProcessedMigrations(TestCase):
@@ -55,17 +58,18 @@ class TestProcessedMigrations(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the load_transition_domain command with the specified arguments.
"""
- # noqa here because splitting this up makes it confusing.
- # ES501
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command(
- "load_transition_domain",
- self.migration_json_filename,
- directory=self.test_data_file_location,
- )
+ with less_console_noise():
+ # noqa here because splitting this up makes it confusing.
+ # ES501
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command(
+ "load_transition_domain",
+ self.migration_json_filename,
+ directory=self.test_data_file_location,
+ )
def run_transfer_domains(self):
"""
@@ -74,101 +78,104 @@ class TestProcessedMigrations(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the load_transition_domain command with the specified arguments.
"""
- call_command("transfer_transition_domains_to_domains")
+ with less_console_noise():
+ call_command("transfer_transition_domains_to_domains")
def test_domain_idempotent(self):
"""
This test ensures that the domain transfer process
is idempotent on Domain and DomainInformation.
"""
- unchanged_domain, _ = Domain.objects.get_or_create(
- name="testdomain.gov",
- state=Domain.State.READY,
- expiration_date=datetime.date(2000, 1, 1),
- )
- unchanged_domain_information, _ = DomainInformation.objects.get_or_create(
- domain=unchanged_domain, organization_name="test org name", creator=self.user
- )
- self.run_load_domains()
+ with less_console_noise():
+ unchanged_domain, _ = Domain.objects.get_or_create(
+ name="testdomain.gov",
+ state=Domain.State.READY,
+ expiration_date=datetime.date(2000, 1, 1),
+ )
+ unchanged_domain_information, _ = DomainInformation.objects.get_or_create(
+ domain=unchanged_domain, organization_name="test org name", creator=self.user
+ )
+ self.run_load_domains()
- # Test that a given TransitionDomain isn't set to "processed"
- transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
- self.assertFalse(transition_domain_object.processed)
+ # Test that a given TransitionDomain isn't set to "processed"
+ transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
+ self.assertFalse(transition_domain_object.processed)
- self.run_transfer_domains()
+ self.run_transfer_domains()
- # Test that old data isn't corrupted
- actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
- actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
- self.assertEqual(unchanged_domain, actual_unchanged)
- self.assertEqual(unchanged_domain_information, actual_unchanged_information)
+ # Test that old data isn't corrupted
+ actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
+ actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
+ self.assertEqual(unchanged_domain, actual_unchanged)
+ self.assertEqual(unchanged_domain_information, actual_unchanged_information)
- # Test that a given TransitionDomain is set to "processed" after we transfer domains
- transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
- self.assertTrue(transition_domain_object.processed)
+ # Test that a given TransitionDomain is set to "processed" after we transfer domains
+ transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
+ self.assertTrue(transition_domain_object.processed)
- # Manually change Domain/DomainInformation objects
- changed_domain = Domain.objects.filter(name="fakewebsite3.gov").get()
- changed_domain.expiration_date = datetime.date(1999, 1, 1)
+ # Manually change Domain/DomainInformation objects
+ changed_domain = Domain.objects.filter(name="fakewebsite3.gov").get()
+ changed_domain.expiration_date = datetime.date(1999, 1, 1)
- changed_domain.save()
+ changed_domain.save()
- changed_domain_information = DomainInformation.objects.filter(domain=changed_domain).get()
- changed_domain_information.organization_name = "changed"
+ changed_domain_information = DomainInformation.objects.filter(domain=changed_domain).get()
+ changed_domain_information.organization_name = "changed"
- changed_domain_information.save()
+ changed_domain_information.save()
- # Rerun transfer domains
- self.run_transfer_domains()
+ # Rerun transfer domains
+ self.run_transfer_domains()
- # Test that old data isn't corrupted after running this twice
- actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
- actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
- self.assertEqual(unchanged_domain, actual_unchanged)
- self.assertEqual(unchanged_domain_information, actual_unchanged_information)
+ # Test that old data isn't corrupted after running this twice
+ actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
+ actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
+ self.assertEqual(unchanged_domain, actual_unchanged)
+ self.assertEqual(unchanged_domain_information, actual_unchanged_information)
- # Ensure that domain hasn't changed
- actual_domain = Domain.objects.filter(name="fakewebsite3.gov").get()
- self.assertEqual(changed_domain, actual_domain)
+ # Ensure that domain hasn't changed
+ actual_domain = Domain.objects.filter(name="fakewebsite3.gov").get()
+ self.assertEqual(changed_domain, actual_domain)
- # Ensure that DomainInformation hasn't changed
- actual_domain_information = DomainInformation.objects.filter(domain=changed_domain).get()
- self.assertEqual(changed_domain_information, actual_domain_information)
+ # Ensure that DomainInformation hasn't changed
+ actual_domain_information = DomainInformation.objects.filter(domain=changed_domain).get()
+ self.assertEqual(changed_domain_information, actual_domain_information)
def test_transition_domain_is_processed(self):
"""
This test checks if a domain is correctly marked as processed in the transition.
"""
- old_transition_domain, _ = TransitionDomain.objects.get_or_create(domain_name="testdomain.gov")
- # Asser that old records default to 'True'
- self.assertTrue(old_transition_domain.processed)
+ with less_console_noise():
+ old_transition_domain, _ = TransitionDomain.objects.get_or_create(domain_name="testdomain.gov")
+ # Asser that old records default to 'True'
+ self.assertTrue(old_transition_domain.processed)
- unchanged_domain, _ = Domain.objects.get_or_create(
- name="testdomain.gov",
- state=Domain.State.READY,
- expiration_date=datetime.date(2000, 1, 1),
- )
- unchanged_domain_information, _ = DomainInformation.objects.get_or_create(
- domain=unchanged_domain, organization_name="test org name", creator=self.user
- )
- self.run_load_domains()
+ unchanged_domain, _ = Domain.objects.get_or_create(
+ name="testdomain.gov",
+ state=Domain.State.READY,
+ expiration_date=datetime.date(2000, 1, 1),
+ )
+ unchanged_domain_information, _ = DomainInformation.objects.get_or_create(
+ domain=unchanged_domain, organization_name="test org name", creator=self.user
+ )
+ self.run_load_domains()
- # Test that a given TransitionDomain isn't set to "processed"
- transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
- self.assertFalse(transition_domain_object.processed)
+ # Test that a given TransitionDomain isn't set to "processed"
+ transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
+ self.assertFalse(transition_domain_object.processed)
- self.run_transfer_domains()
+ self.run_transfer_domains()
- # Test that old data isn't corrupted
- actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
- actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
- self.assertEqual(unchanged_domain, actual_unchanged)
- self.assertTrue(old_transition_domain.processed)
- self.assertEqual(unchanged_domain_information, actual_unchanged_information)
+ # Test that old data isn't corrupted
+ actual_unchanged = Domain.objects.filter(name="testdomain.gov").get()
+ actual_unchanged_information = DomainInformation.objects.filter(domain=actual_unchanged).get()
+ self.assertEqual(unchanged_domain, actual_unchanged)
+ self.assertTrue(old_transition_domain.processed)
+ self.assertEqual(unchanged_domain_information, actual_unchanged_information)
- # Test that a given TransitionDomain is set to "processed" after we transfer domains
- transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
- self.assertTrue(transition_domain_object.processed)
+ # Test that a given TransitionDomain is set to "processed" after we transfer domains
+ transition_domain_object = TransitionDomain.objects.get(domain_name="fakewebsite3.gov")
+ self.assertTrue(transition_domain_object.processed)
class TestOrganizationMigration(TestCase):
@@ -200,17 +207,18 @@ class TestOrganizationMigration(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the load_transition_domain command with the specified arguments.
"""
- # noqa here because splitting this up makes it confusing.
- # ES501
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command(
- "load_transition_domain",
- self.migration_json_filename,
- directory=self.test_data_file_location,
- )
+ with less_console_noise():
+ # noqa here because splitting this up makes it confusing.
+ # ES501
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command(
+ "load_transition_domain",
+ self.migration_json_filename,
+ directory=self.test_data_file_location,
+ )
def run_transfer_domains(self):
"""
@@ -219,7 +227,8 @@ class TestOrganizationMigration(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the load_transition_domain command with the specified arguments.
"""
- call_command("transfer_transition_domains_to_domains")
+ with less_console_noise():
+ call_command("transfer_transition_domains_to_domains")
def run_load_organization_data(self):
"""
@@ -232,17 +241,18 @@ class TestOrganizationMigration(TestCase):
The 'call_command' function from Django's management framework is then used to
execute the load_organization_data command with the specified arguments.
"""
- # noqa here (E501) because splitting this up makes it
- # confusing to read.
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command(
- "load_organization_data",
- self.migration_json_filename,
- directory=self.test_data_file_location,
- )
+ with less_console_noise():
+ # noqa here (E501) because splitting this up makes it
+ # confusing to read.
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ call_command(
+ "load_organization_data",
+ self.migration_json_filename,
+ directory=self.test_data_file_location,
+ )
def compare_tables(
self,
@@ -256,7 +266,6 @@ class TestOrganizationMigration(TestCase):
"""Does a diff between the transition_domain and the following tables:
domain, domain_information and the domain_invitation.
Verifies that the data loaded correctly."""
-
missing_domains = []
duplicate_domains = []
missing_domain_informations = []
@@ -300,59 +309,64 @@ class TestOrganizationMigration(TestCase):
3. Checks that the data has been loaded as expected.
The expected result is a set of TransitionDomain objects with specific attributes.
- The test fetches the actual TransitionDomain objects from the database and compares them with the expected objects.
- """ # noqa - E501 (harder to read)
- # == First, parse all existing data == #
- self.run_load_domains()
- self.run_transfer_domains()
+ The test fetches the actual TransitionDomain objects from the database and compares them with
+ the expected objects.
+ """
+ with less_console_noise():
+ # noqa - E501 (harder to read)
+ # == First, parse all existing data == #
+ self.run_load_domains()
+ self.run_transfer_domains()
- # == Second, try adding org data to it == #
- self.run_load_organization_data()
+ # == Second, try adding org data to it == #
+ self.run_load_organization_data()
- # == Third, test that we've loaded data as we expect == #
- transition_domains = TransitionDomain.objects.filter(domain_name="fakewebsite2.gov")
+ # == Third, test that we've loaded data as we expect == #
+ transition_domains = TransitionDomain.objects.filter(domain_name="fakewebsite2.gov")
- # Should return three objects (three unique emails)
- self.assertEqual(transition_domains.count(), 3)
+ # Should return three objects (three unique emails)
+ self.assertEqual(transition_domains.count(), 3)
- # Lets test the first one
- transition = transition_domains.first()
- expected_transition_domain = TransitionDomain(
- username="alexandra.bobbitt5@test.com",
- domain_name="fakewebsite2.gov",
- status="on hold",
- email_sent=True,
- organization_type="Federal",
- organization_name="Fanoodle",
- federal_type="Executive",
- federal_agency="Department of Commerce",
- epp_creation_date=datetime.date(2004, 5, 7),
- epp_expiration_date=datetime.date(2023, 9, 30),
- first_name="Seline",
- middle_name="testmiddle2",
- last_name="Tower",
- title=None,
- email="stower3@answers.com",
- phone="151-539-6028",
- address_line="93001 Arizona Drive",
- city="Columbus",
- state_territory="Oh",
- zipcode="43268",
- )
- expected_transition_domain.id = transition.id
+ # Lets test the first one
+ transition = transition_domains.first()
+ expected_transition_domain = TransitionDomain(
+ username="alexandra.bobbitt5@test.com",
+ domain_name="fakewebsite2.gov",
+ status="on hold",
+ email_sent=True,
+ organization_type="Federal",
+ organization_name="Fanoodle",
+ federal_type="Executive",
+ federal_agency="Department of Commerce",
+ epp_creation_date=datetime.date(2004, 5, 7),
+ epp_expiration_date=datetime.date(2023, 9, 30),
+ first_name="Seline",
+ middle_name="testmiddle2",
+ last_name="Tower",
+ title=None,
+ email="stower3@answers.com",
+ phone="151-539-6028",
+ address_line="93001 Arizona Drive",
+ city="Columbus",
+ state_territory="Oh",
+ zipcode="43268",
+ )
+ expected_transition_domain.id = transition.id
- self.assertEqual(transition, expected_transition_domain)
+ self.assertEqual(transition, expected_transition_domain)
def test_transition_domain_status_unknown(self):
"""
Test that a domain in unknown status can be loaded
- """ # noqa - E501 (harder to read)
- # == First, parse all existing data == #
- self.run_load_domains()
- self.run_transfer_domains()
+ """
+ with less_console_noise():
+ # noqa - E501 (harder to read)
+ # == First, parse all existing data == #
+ self.run_load_domains()
+ self.run_transfer_domains()
- domain_object = Domain.objects.get(name="fakewebsite3.gov")
- self.assertEqual(domain_object.state, Domain.State.UNKNOWN)
+ domain_object = Domain.objects.get(name="fakewebsite3.gov")
+ self.assertEqual(domain_object.state, Domain.State.UNKNOWN)
def test_load_organization_data_domain_information(self):
"""
@@ -367,35 +381,38 @@ class TestOrganizationMigration(TestCase):
The test fetches the actual DomainInformation object from the database
and compares it with the expected object.
"""
- # == First, parse all existing data == #
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ # == First, parse all existing data == #
+ self.run_load_domains()
+ self.run_transfer_domains()
- # == Second, try adding org data to it == #
- self.run_load_organization_data()
+ # == Second, try adding org data to it == #
+ self.run_load_organization_data()
- # == Third, test that we've loaded data as we expect == #
- _domain = Domain.objects.filter(name="fakewebsite2.gov").get()
- domain_information = DomainInformation.objects.filter(domain=_domain).get()
+ # == Third, test that we've loaded data as we expect == #
+ _domain = Domain.objects.filter(name="fakewebsite2.gov").get()
+ domain_information = DomainInformation.objects.filter(domain=_domain).get()
- expected_creator = User.objects.filter(username="System").get()
- expected_ao = Contact.objects.filter(first_name="Seline", middle_name="testmiddle2", last_name="Tower").get()
- expected_domain_information = DomainInformation(
- creator=expected_creator,
- organization_type="federal",
- federal_agency="Department of Commerce",
- federal_type="executive",
- organization_name="Fanoodle",
- address_line1="93001 Arizona Drive",
- city="Columbus",
- state_territory="Oh",
- zipcode="43268",
- authorizing_official=expected_ao,
- domain=_domain,
- )
- # Given that these are different objects, this needs to be set
- expected_domain_information.id = domain_information.id
- self.assertEqual(domain_information, expected_domain_information)
+ expected_creator = User.objects.filter(username="System").get()
+ expected_ao = Contact.objects.filter(
+ first_name="Seline", middle_name="testmiddle2", last_name="Tower"
+ ).get()
+ expected_domain_information = DomainInformation(
+ creator=expected_creator,
+ organization_type="federal",
+ federal_agency="Department of Commerce",
+ federal_type="executive",
+ organization_name="Fanoodle",
+ address_line1="93001 Arizona Drive",
+ city="Columbus",
+ state_territory="Oh",
+ zipcode="43268",
+ authorizing_official=expected_ao,
+ domain=_domain,
+ )
+ # Given that these are different objects, this needs to be set
+ expected_domain_information.id = domain_information.id
+ self.assertEqual(domain_information, expected_domain_information)
def test_load_organization_data_preserves_existing_data(self):
"""
@@ -410,44 +427,47 @@ class TestOrganizationMigration(TestCase):
The expected result is that the DomainInformation object retains its pre-existing data
after the load_organization_data method is run.
"""
- # == First, parse all existing data == #
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ # == First, parse all existing data == #
+ self.run_load_domains()
+ self.run_transfer_domains()
- # == Second, try add prexisting fake data == #
- _domain_old = Domain.objects.filter(name="fakewebsite2.gov").get()
- domain_information_old = DomainInformation.objects.filter(domain=_domain_old).get()
- domain_information_old.address_line1 = "93001 Galactic Way"
- domain_information_old.city = "Olympus"
- domain_information_old.state_territory = "MA"
- domain_information_old.zipcode = "12345"
- domain_information_old.save()
+ # == Second, try add prexisting fake data == #
+ _domain_old = Domain.objects.filter(name="fakewebsite2.gov").get()
+ domain_information_old = DomainInformation.objects.filter(domain=_domain_old).get()
+ domain_information_old.address_line1 = "93001 Galactic Way"
+ domain_information_old.city = "Olympus"
+ domain_information_old.state_territory = "MA"
+ domain_information_old.zipcode = "12345"
+ domain_information_old.save()
- # == Third, try running the script == #
- self.run_load_organization_data()
+ # == Third, try running the script == #
+ self.run_load_organization_data()
- # == Fourth, test that no data is overwritten as we expect == #
- _domain = Domain.objects.filter(name="fakewebsite2.gov").get()
- domain_information = DomainInformation.objects.filter(domain=_domain).get()
+ # == Fourth, test that no data is overwritten as we expect == #
+ _domain = Domain.objects.filter(name="fakewebsite2.gov").get()
+ domain_information = DomainInformation.objects.filter(domain=_domain).get()
- expected_creator = User.objects.filter(username="System").get()
- expected_ao = Contact.objects.filter(first_name="Seline", middle_name="testmiddle2", last_name="Tower").get()
- expected_domain_information = DomainInformation(
- creator=expected_creator,
- organization_type="federal",
- federal_agency="Department of Commerce",
- federal_type="executive",
- organization_name="Fanoodle",
- address_line1="93001 Galactic Way",
- city="Olympus",
- state_territory="MA",
- zipcode="12345",
- authorizing_official=expected_ao,
- domain=_domain,
- )
- # Given that these are different objects, this needs to be set
- expected_domain_information.id = domain_information.id
- self.assertEqual(domain_information, expected_domain_information)
+ expected_creator = User.objects.filter(username="System").get()
+ expected_ao = Contact.objects.filter(
+ first_name="Seline", middle_name="testmiddle2", last_name="Tower"
+ ).get()
+ expected_domain_information = DomainInformation(
+ creator=expected_creator,
+ organization_type="federal",
+ federal_agency="Department of Commerce",
+ federal_type="executive",
+ organization_name="Fanoodle",
+ address_line1="93001 Galactic Way",
+ city="Olympus",
+ state_territory="MA",
+ zipcode="12345",
+ authorizing_official=expected_ao,
+ domain=_domain,
+ )
+ # Given that these are different objects, this needs to be set
+ expected_domain_information.id = domain_information.id
+ self.assertEqual(domain_information, expected_domain_information)
def test_load_organization_data_integrity(self):
"""
@@ -462,29 +482,30 @@ class TestOrganizationMigration(TestCase):
The expected result is that the counts of objects in the database
match the expected counts, indicating that the data has not been corrupted.
"""
- # First, parse all existing data
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ # First, parse all existing data
+ self.run_load_domains()
+ self.run_transfer_domains()
- # Second, try adding org data to it
- self.run_load_organization_data()
+ # Second, try adding org data to it
+ self.run_load_organization_data()
- # Third, test that we didn't corrupt any data
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
+ # Third, test that we didn't corrupt any data
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ )
class TestMigrations(TestCase):
@@ -521,39 +542,42 @@ class TestMigrations(TestCase):
UserDomainRole.objects.all().delete()
def run_load_domains(self):
- # noqa here because splitting this up makes it confusing.
- # ES501
- with patch(
- "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
- return_value=True,
- ):
- call_command(
- "load_transition_domain",
- self.migration_json_filename,
- directory=self.test_data_file_location,
- )
-
- def run_transfer_domains(self):
- call_command("transfer_transition_domains_to_domains")
-
- def run_master_script(self):
- # noqa here (E501) because splitting this up makes it
- # confusing to read.
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ # noqa here because splitting this up makes it confusing.
+ # ES501
with patch(
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
return_value=True,
):
- with patch("registrar.utility.email.send_templated_email", return_value=None):
- call_command(
- "master_domain_migrations",
- runMigrations=True,
- migrationDirectory=self.test_data_file_location,
- migrationJSON=self.migration_json_filename,
- disablePrompts=True,
- )
- print(f"here: {mock_client.EMAILS_SENT}")
+ call_command(
+ "load_transition_domain",
+ self.migration_json_filename,
+ directory=self.test_data_file_location,
+ )
+
+ def run_transfer_domains(self):
+ with less_console_noise():
+ call_command("transfer_transition_domains_to_domains")
+
+ def run_master_script(self):
+ with less_console_noise():
+ # noqa here (E501) because splitting this up makes it
+ # confusing to read.
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with patch(
+ "registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
+ return_value=True,
+ ):
+ with patch("registrar.utility.email.send_templated_email", return_value=None):
+ call_command(
+ "master_domain_migrations",
+ runMigrations=True,
+ migrationDirectory=self.test_data_file_location,
+ migrationJSON=self.migration_json_filename,
+ disablePrompts=True,
+ )
+ logger.debug(f"here: {mock_client.EMAILS_SENT}")
def compare_tables(
self,
@@ -607,7 +631,7 @@ class TestMigrations(TestCase):
total_domain_informations = len(DomainInformation.objects.all())
total_domain_invitations = len(DomainInvitation.objects.all())
- print(
+ logger.debug(
f"""
total_missing_domains = {len(missing_domains)}
total_duplicate_domains = {len(duplicate_domains)}
@@ -636,225 +660,230 @@ class TestMigrations(TestCase):
follow best practice of limiting the number of assertions per test.
But for now, this will double-check that the script
works as intended."""
+ with less_console_noise():
+ self.run_master_script()
- self.run_master_script()
+ # STEP 2: (analyze the tables just like the
+ # migration script does, but add assert statements)
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
+ expected_total_domain_invitations = 8
- # STEP 2: (analyze the tables just like the
- # migration script does, but add assert statements)
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
- expected_total_domain_invitations = 8
-
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- # we expect 1 missing invite from anomaly.gov (an injected error)
- expected_missing_domain_invitations = 1
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ # we expect 1 missing invite from anomaly.gov (an injected error)
+ expected_missing_domain_invitations = 1
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
def test_load_empty_transition_domain(self):
"""Loads TransitionDomains without additional data"""
- self.run_load_domains()
+ with less_console_noise():
+ self.run_load_domains()
- # STEP 2: (analyze the tables just like the migration
- # script does, but add assert statements)
- expected_total_transition_domains = 9
- expected_total_domains = 0
- expected_total_domain_informations = 0
- expected_total_domain_invitations = 0
+ # STEP 2: (analyze the tables just like the migration
+ # script does, but add assert statements)
+ expected_total_transition_domains = 9
+ expected_total_domains = 0
+ expected_total_domain_informations = 0
+ expected_total_domain_invitations = 0
- expected_missing_domains = 9
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 9
- expected_missing_domain_invitations = 9
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 9
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 9
+ expected_missing_domain_invitations = 9
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
def test_load_full_domain(self):
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ self.run_load_domains()
+ self.run_transfer_domains()
- # Analyze the tables
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
- expected_total_domain_invitations = 8
+ # Analyze the tables
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
+ expected_total_domain_invitations = 8
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- expected_missing_domain_invitations = 1
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ expected_missing_domain_invitations = 1
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
- # Test created domains
- anomaly_domains = Domain.objects.filter(name="anomaly.gov")
- self.assertEqual(anomaly_domains.count(), 1)
- anomaly = anomaly_domains.get()
+ # Test created domains
+ anomaly_domains = Domain.objects.filter(name="anomaly.gov")
+ self.assertEqual(anomaly_domains.count(), 1)
+ anomaly = anomaly_domains.get()
- self.assertEqual(anomaly.expiration_date, datetime.date(2023, 3, 9))
+ self.assertEqual(anomaly.expiration_date, datetime.date(2023, 3, 9))
- self.assertEqual(anomaly.name, "anomaly.gov")
- self.assertEqual(anomaly.state, "ready")
+ self.assertEqual(anomaly.name, "anomaly.gov")
+ self.assertEqual(anomaly.state, "ready")
- testdomain_domains = Domain.objects.filter(name="fakewebsite2.gov")
- self.assertEqual(testdomain_domains.count(), 1)
+ testdomain_domains = Domain.objects.filter(name="fakewebsite2.gov")
+ self.assertEqual(testdomain_domains.count(), 1)
- testdomain = testdomain_domains.get()
+ testdomain = testdomain_domains.get()
- self.assertEqual(testdomain.expiration_date, datetime.date(2023, 9, 30))
- self.assertEqual(testdomain.name, "fakewebsite2.gov")
- self.assertEqual(testdomain.state, "on hold")
+ self.assertEqual(testdomain.expiration_date, datetime.date(2023, 9, 30))
+ self.assertEqual(testdomain.name, "fakewebsite2.gov")
+ self.assertEqual(testdomain.state, "on hold")
def test_load_full_domain_information(self):
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ self.run_load_domains()
+ self.run_transfer_domains()
- # Analyze the tables
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
- expected_total_domain_invitations = 8
+ # Analyze the tables
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
+ expected_total_domain_invitations = 8
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- expected_missing_domain_invitations = 1
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ expected_missing_domain_invitations = 1
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
- # Test created Domain Information objects
- domain = Domain.objects.filter(name="anomaly.gov").get()
- anomaly_domain_infos = DomainInformation.objects.filter(domain=domain)
+ # Test created Domain Information objects
+ domain = Domain.objects.filter(name="anomaly.gov").get()
+ anomaly_domain_infos = DomainInformation.objects.filter(domain=domain)
- self.assertEqual(anomaly_domain_infos.count(), 1)
+ self.assertEqual(anomaly_domain_infos.count(), 1)
- # This domain should be pretty barebones. Something isnt
- # parsing right if we get a lot of data.
- anomaly = anomaly_domain_infos.get()
- self.assertEqual(anomaly.organization_name, "Flashdog")
- self.assertEqual(anomaly.organization_type, None)
- self.assertEqual(anomaly.federal_agency, None)
- self.assertEqual(anomaly.federal_type, None)
+ # This domain should be pretty barebones. Something isnt
+ # parsing right if we get a lot of data.
+ anomaly = anomaly_domain_infos.get()
+ self.assertEqual(anomaly.organization_name, "Flashdog")
+ self.assertEqual(anomaly.organization_type, None)
+ self.assertEqual(anomaly.federal_agency, None)
+ self.assertEqual(anomaly.federal_type, None)
- # Check for the "system" creator user
- Users = User.objects.filter(username="System")
- self.assertEqual(Users.count(), 1)
- self.assertEqual(anomaly.creator, Users.get())
+ # Check for the "system" creator user
+ Users = User.objects.filter(username="System")
+ self.assertEqual(Users.count(), 1)
+ self.assertEqual(anomaly.creator, Users.get())
- domain = Domain.objects.filter(name="fakewebsite2.gov").get()
- fakewebsite_domain_infos = DomainInformation.objects.filter(domain=domain)
- self.assertEqual(fakewebsite_domain_infos.count(), 1)
+ domain = Domain.objects.filter(name="fakewebsite2.gov").get()
+ fakewebsite_domain_infos = DomainInformation.objects.filter(domain=domain)
+ self.assertEqual(fakewebsite_domain_infos.count(), 1)
- fakewebsite = fakewebsite_domain_infos.get()
- self.assertEqual(fakewebsite.organization_name, "Fanoodle")
- self.assertEqual(fakewebsite.organization_type, "federal")
- self.assertEqual(fakewebsite.federal_agency, "Department of Commerce")
- self.assertEqual(fakewebsite.federal_type, "executive")
+ fakewebsite = fakewebsite_domain_infos.get()
+ self.assertEqual(fakewebsite.organization_name, "Fanoodle")
+ self.assertEqual(fakewebsite.organization_type, "federal")
+ self.assertEqual(fakewebsite.federal_agency, "Department of Commerce")
+ self.assertEqual(fakewebsite.federal_type, "executive")
- ao = fakewebsite.authorizing_official
+ ao = fakewebsite.authorizing_official
- self.assertEqual(ao.first_name, "Seline")
- self.assertEqual(ao.middle_name, "testmiddle2")
- self.assertEqual(ao.last_name, "Tower")
- self.assertEqual(ao.email, "stower3@answers.com")
- self.assertEqual(ao.phone, "151-539-6028")
+ self.assertEqual(ao.first_name, "Seline")
+ self.assertEqual(ao.middle_name, "testmiddle2")
+ self.assertEqual(ao.last_name, "Tower")
+ self.assertEqual(ao.email, "stower3@answers.com")
+ self.assertEqual(ao.phone, "151-539-6028")
- # Check for the "system" creator user
- Users = User.objects.filter(username="System")
- self.assertEqual(Users.count(), 1)
- self.assertEqual(anomaly.creator, Users.get())
+ # Check for the "system" creator user
+ Users = User.objects.filter(username="System")
+ self.assertEqual(Users.count(), 1)
+ self.assertEqual(anomaly.creator, Users.get())
def test_transfer_transition_domains_to_domains(self):
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ self.run_load_domains()
+ self.run_transfer_domains()
- # Analyze the tables
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
- expected_total_domain_invitations = 8
+ # Analyze the tables
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
+ expected_total_domain_invitations = 8
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- expected_missing_domain_invitations = 1
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ expected_missing_domain_invitations = 1
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
def test_logins(self):
- # TODO: setup manually instead of calling other scripts
- self.run_load_domains()
- self.run_transfer_domains()
+ with less_console_noise():
+ # TODO: setup manually instead of calling other scripts
+ self.run_load_domains()
+ self.run_transfer_domains()
- # Simluate Logins
- for invite in DomainInvitation.objects.all():
- # get a user with this email address
- user, user_created = User.objects.get_or_create(email=invite.email, username=invite.email)
- user.on_each_login()
+ # Simluate Logins
+ for invite in DomainInvitation.objects.all():
+ # get a user with this email address
+ user, user_created = User.objects.get_or_create(email=invite.email, username=invite.email)
+ user.on_each_login()
- # Analyze the tables
- expected_total_transition_domains = 9
- expected_total_domains = 5
- expected_total_domain_informations = 5
- expected_total_domain_invitations = 8
+ # Analyze the tables
+ expected_total_transition_domains = 9
+ expected_total_domains = 5
+ expected_total_domain_informations = 5
+ expected_total_domain_invitations = 8
- expected_missing_domains = 0
- expected_duplicate_domains = 0
- expected_missing_domain_informations = 0
- expected_missing_domain_invitations = 1
- self.compare_tables(
- expected_total_transition_domains,
- expected_total_domains,
- expected_total_domain_informations,
- expected_total_domain_invitations,
- expected_missing_domains,
- expected_duplicate_domains,
- expected_missing_domain_informations,
- expected_missing_domain_invitations,
- )
+ expected_missing_domains = 0
+ expected_duplicate_domains = 0
+ expected_missing_domain_informations = 0
+ expected_missing_domain_invitations = 1
+ self.compare_tables(
+ expected_total_transition_domains,
+ expected_total_domains,
+ expected_total_domain_informations,
+ expected_total_domain_invitations,
+ expected_missing_domains,
+ expected_duplicate_domains,
+ expected_missing_domain_informations,
+ expected_missing_domain_invitations,
+ )
@boto3_mocking.patching
def test_send_domain_invitations_email(self):
diff --git a/src/registrar/tests/test_url_auth.py b/src/registrar/tests/test_url_auth.py
index 34f80ac44..3e0514a85 100644
--- a/src/registrar/tests/test_url_auth.py
+++ b/src/registrar/tests/test_url_auth.py
@@ -23,6 +23,7 @@ SAMPLE_KWARGS = {
"content_type_id": "2",
"object_id": "3",
"domain": "whitehouse.gov",
+ "user_pk": "1",
}
# Our test suite will ignore some namespaces.
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index f8373710c..450993e5c 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1,44 +1,17 @@
-from unittest import skip
-from unittest.mock import MagicMock, ANY, patch
-
-from django.conf import settings
from django.test import Client, TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
-from .common import MockEppLib, MockSESClient, completed_application, create_user # type: ignore
-from django_webtest import WebTest # type: ignore
-import boto3_mocking # type: ignore
+from .common import MockEppLib # type: ignore
-from registrar.utility.errors import (
- NameserverError,
- NameserverErrorCodes,
- SecurityEmailError,
- SecurityEmailErrorCodes,
- GenericError,
- GenericErrorCodes,
- DsDataError,
- DsDataErrorCodes,
-)
from registrar.models import (
DomainApplication,
- Domain,
DomainInformation,
DraftDomain,
- DomainInvitation,
Contact,
- PublicContact,
- Host,
- HostIP,
- Website,
- UserDomainRole,
User,
)
-from registrar.views.application import ApplicationWizard, Step
-from datetime import date, datetime, timedelta
-from django.utils import timezone
-
from .common import less_console_noise
import logging
@@ -159,32 +132,33 @@ class LoggedInTests(TestWithUser):
# Given that we are including a subset of items that can be deleted while excluding the rest,
# subTest is appropriate here as otherwise we would need many duplicate tests for the same reason.
- draft_domain = DraftDomain.objects.create(name="igorville.gov")
- for status in DomainApplication.ApplicationStatus:
- if status not in [
- DomainApplication.ApplicationStatus.STARTED,
- DomainApplication.ApplicationStatus.WITHDRAWN,
- ]:
- with self.subTest(status=status):
- application = DomainApplication.objects.create(
- creator=self.user, requested_domain=draft_domain, status=status
- )
+ with less_console_noise():
+ draft_domain = DraftDomain.objects.create(name="igorville.gov")
+ for status in DomainApplication.ApplicationStatus:
+ if status not in [
+ DomainApplication.ApplicationStatus.STARTED,
+ DomainApplication.ApplicationStatus.WITHDRAWN,
+ ]:
+ with self.subTest(status=status):
+ application = DomainApplication.objects.create(
+ creator=self.user, requested_domain=draft_domain, status=status
+ )
- # Trigger the delete logic
- response = self.client.post(
- reverse("application-delete", kwargs={"pk": application.pk}), follow=True
- )
+ # Trigger the delete logic
+ response = self.client.post(
+ reverse("application-delete", kwargs={"pk": application.pk}), follow=True
+ )
- # Check for a 403 error - the end user should not be allowed to do this
- self.assertEqual(response.status_code, 403)
+ # Check for a 403 error - the end user should not be allowed to do this
+ self.assertEqual(response.status_code, 403)
- desired_application = DomainApplication.objects.filter(requested_domain=draft_domain)
+ desired_application = DomainApplication.objects.filter(requested_domain=draft_domain)
- # Make sure the DomainApplication wasn't deleted
- self.assertEqual(desired_application.count(), 1)
+ # Make sure the DomainApplication wasn't deleted
+ self.assertEqual(desired_application.count(), 1)
- # clean up
- application.delete()
+ # clean up
+ application.delete()
def test_home_deletes_domain_application_and_orphans(self):
"""Tests if delete for DomainApplication deletes orphaned Contact objects"""
@@ -329,3569 +303,4 @@ class LoggedInTests(TestWithUser):
with less_console_noise():
response = self.client.get("/request/", follow=True)
- print(response.status_code)
self.assertEqual(response.status_code, 403)
-
-
-class DomainApplicationTests(TestWithUser, WebTest):
-
- """Webtests for domain application to test filling and submitting."""
-
- # Doesn't work with CSRF checking
- # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest
- csrf_checks = False
-
- def setUp(self):
- super().setUp()
- self.app.set_user(self.user.username)
- self.TITLES = ApplicationWizard.TITLES
-
- def test_application_form_intro_acknowledgement(self):
- """Tests that user is presented with intro acknowledgement page"""
- intro_page = self.app.get(reverse("application:"))
- self.assertContains(intro_page, "You’re about to start your .gov domain request")
-
- def test_application_form_intro_is_skipped_when_edit_access(self):
- """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'"""
- completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user)
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- # click the "Edit" link
- detail_page = home_page.click("Edit", index=0)
- # Check that the response is a redirect
- self.assertEqual(detail_page.status_code, 302)
- # You can access the 'Location' header to get the redirect URL
- redirect_url = detail_page.url
- self.assertEqual(redirect_url, "/request/organization_type/")
-
- def test_application_form_empty_submit(self):
- """Tests empty submit on the first page after the acknowledgement page"""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # submitting should get back the same page if the required field is empty
- result = type_page.forms[0].submit()
- self.assertIn("What kind of U.S.-based government organization do you represent?", result)
-
- def test_application_multiple_applications_exist(self):
- """Test that an info message appears when user has multiple applications already"""
- # create and submit an application
- application = completed_application(user=self.user)
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- application.submit()
- application.save()
-
- # now, attempt to create another one
- with less_console_noise():
- intro_page = self.app.get(reverse("application:"))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- self.assertContains(type_page, "You cannot submit this request yet")
-
- @boto3_mocking.patching
- def test_application_form_submission(self):
- """
- Can fill out the entire form and submit.
- As we add additional form pages, we need to include them here to make
- this test work.
-
- This test also looks for the long organization name on the summary page.
-
- This also tests for the presence of a modal trigger and the dynamic test
- in the modal header on the submit page.
- """
- num_pages_tested = 0
- # elections, type_of_work, tribal_government
- SKIPPED_PAGES = 3
- num_pages = len(self.TITLES) - SKIPPED_PAGES
-
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # ---- TYPE PAGE ----
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "federal"
- # test next button and validate data
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
- # should see results in db
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.organization_type, "federal")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(type_result.status_code, 302)
- self.assertEqual(type_result["Location"], "/request/organization_federal/")
- num_pages_tested += 1
-
- # ---- FEDERAL BRANCH PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- federal_page = type_result.follow()
- federal_form = federal_page.forms[0]
- federal_form["organization_federal-federal_type"] = "executive"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_result = federal_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.federal_type, "executive")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(federal_result.status_code, 302)
- self.assertEqual(federal_result["Location"], "/request/organization_contact/")
- num_pages_tested += 1
-
- # ---- ORG CONTACT PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_page = federal_result.follow()
- org_contact_form = org_contact_page.forms[0]
- # federal agency so we have to fill in federal_agency
- org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
- org_contact_form["organization_contact-organization_name"] = "Testorg"
- org_contact_form["organization_contact-address_line1"] = "address 1"
- org_contact_form["organization_contact-address_line2"] = "address 2"
- org_contact_form["organization_contact-city"] = "NYC"
- org_contact_form["organization_contact-state_territory"] = "NY"
- org_contact_form["organization_contact-zipcode"] = "10002"
- org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_result = org_contact_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.organization_name, "Testorg")
- self.assertEqual(application.address_line1, "address 1")
- self.assertEqual(application.address_line2, "address 2")
- self.assertEqual(application.city, "NYC")
- self.assertEqual(application.state_territory, "NY")
- self.assertEqual(application.zipcode, "10002")
- self.assertEqual(application.urbanization, "URB Royal Oaks")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(org_contact_result.status_code, 302)
- self.assertEqual(org_contact_result["Location"], "/request/authorizing_official/")
- num_pages_tested += 1
-
- # ---- AUTHORIZING OFFICIAL PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page = org_contact_result.follow()
- ao_form = ao_page.forms[0]
- ao_form["authorizing_official-first_name"] = "Testy ATO"
- ao_form["authorizing_official-last_name"] = "Tester ATO"
- ao_form["authorizing_official-title"] = "Chief Tester"
- ao_form["authorizing_official-email"] = "testy@town.com"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_result = ao_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.authorizing_official.first_name, "Testy ATO")
- self.assertEqual(application.authorizing_official.last_name, "Tester ATO")
- self.assertEqual(application.authorizing_official.title, "Chief Tester")
- self.assertEqual(application.authorizing_official.email, "testy@town.com")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(ao_result.status_code, 302)
- self.assertEqual(ao_result["Location"], "/request/current_sites/")
- num_pages_tested += 1
-
- # ---- CURRENT SITES PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_page = ao_result.follow()
- current_sites_form = current_sites_page.forms[0]
- current_sites_form["current_sites-0-website"] = "www.city.com"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_result = current_sites_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(
- application.current_websites.filter(website="http://www.city.com").count(),
- 1,
- )
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(current_sites_result.status_code, 302)
- self.assertEqual(current_sites_result["Location"], "/request/dotgov_domain/")
- num_pages_tested += 1
-
- # ---- DOTGOV DOMAIN PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- dotgov_page = current_sites_result.follow()
- dotgov_form = dotgov_page.forms[0]
- dotgov_form["dotgov_domain-requested_domain"] = "city"
- dotgov_form["dotgov_domain-0-alternative_domain"] = "city1"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- dotgov_result = dotgov_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.requested_domain.name, "city.gov")
- self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1)
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(dotgov_result.status_code, 302)
- self.assertEqual(dotgov_result["Location"], "/request/purpose/")
- num_pages_tested += 1
-
- # ---- PURPOSE PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- purpose_page = dotgov_result.follow()
- purpose_form = purpose_page.forms[0]
- purpose_form["purpose-purpose"] = "For all kinds of things."
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- purpose_result = purpose_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.purpose, "For all kinds of things.")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(purpose_result.status_code, 302)
- self.assertEqual(purpose_result["Location"], "/request/your_contact/")
- num_pages_tested += 1
-
- # ---- YOUR CONTACT INFO PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- your_contact_page = purpose_result.follow()
- your_contact_form = your_contact_page.forms[0]
-
- your_contact_form["your_contact-first_name"] = "Testy you"
- your_contact_form["your_contact-last_name"] = "Tester you"
- your_contact_form["your_contact-title"] = "Admin Tester"
- your_contact_form["your_contact-email"] = "testy-admin@town.com"
- your_contact_form["your_contact-phone"] = "(201) 555 5556"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- your_contact_result = your_contact_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.submitter.first_name, "Testy you")
- self.assertEqual(application.submitter.last_name, "Tester you")
- self.assertEqual(application.submitter.title, "Admin Tester")
- self.assertEqual(application.submitter.email, "testy-admin@town.com")
- self.assertEqual(application.submitter.phone, "(201) 555 5556")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(your_contact_result.status_code, 302)
- self.assertEqual(your_contact_result["Location"], "/request/other_contacts/")
- num_pages_tested += 1
-
- # ---- OTHER CONTACTS PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- other_contacts_page = your_contact_result.follow()
-
- # This page has 3 forms in 1.
- # Let's set the yes/no radios to enable the other contacts fieldsets
- other_contacts_form = other_contacts_page.forms[0]
-
- other_contacts_form["other_contacts-has_other_contacts"] = "True"
-
- other_contacts_form["other_contacts-0-first_name"] = "Testy2"
- other_contacts_form["other_contacts-0-last_name"] = "Tester2"
- other_contacts_form["other_contacts-0-title"] = "Another Tester"
- other_contacts_form["other_contacts-0-email"] = "testy2@town.com"
- other_contacts_form["other_contacts-0-phone"] = "(201) 555 5557"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- other_contacts_result = other_contacts_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(
- application.other_contacts.filter(
- first_name="Testy2",
- last_name="Tester2",
- title="Another Tester",
- email="testy2@town.com",
- phone="(201) 555 5557",
- ).count(),
- 1,
- )
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(other_contacts_result.status_code, 302)
- self.assertEqual(other_contacts_result["Location"], "/request/anything_else/")
- num_pages_tested += 1
-
- # ---- ANYTHING ELSE PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- anything_else_page = other_contacts_result.follow()
- anything_else_form = anything_else_page.forms[0]
-
- anything_else_form["anything_else-anything_else"] = "Nothing else."
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- anything_else_result = anything_else_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.anything_else, "Nothing else.")
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(anything_else_result.status_code, 302)
- self.assertEqual(anything_else_result["Location"], "/request/requirements/")
- num_pages_tested += 1
-
- # ---- REQUIREMENTS PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- requirements_page = anything_else_result.follow()
- requirements_form = requirements_page.forms[0]
-
- requirements_form["requirements-is_policy_acknowledged"] = True
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- requirements_result = requirements_form.submit()
- # validate that data from this step are being saved
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(application.is_policy_acknowledged, True)
- # the post request should return a redirect to the next form in
- # the application
- self.assertEqual(requirements_result.status_code, 302)
- self.assertEqual(requirements_result["Location"], "/request/review/")
- num_pages_tested += 1
-
- # ---- REVIEW AND FINSIHED PAGES ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- review_page = requirements_result.follow()
- review_form = review_page.forms[0]
-
- # Review page contains all the previously entered data
- # Let's make sure the long org name is displayed
- self.assertContains(review_page, "Federal")
- self.assertContains(review_page, "Executive")
- self.assertContains(review_page, "Testorg")
- self.assertContains(review_page, "address 1")
- self.assertContains(review_page, "address 2")
- self.assertContains(review_page, "NYC")
- self.assertContains(review_page, "NY")
- self.assertContains(review_page, "10002")
- self.assertContains(review_page, "URB Royal Oaks")
- self.assertContains(review_page, "Testy ATO")
- self.assertContains(review_page, "Tester ATO")
- self.assertContains(review_page, "Chief Tester")
- self.assertContains(review_page, "testy@town.com")
- self.assertContains(review_page, "city.com")
- self.assertContains(review_page, "city.gov")
- self.assertContains(review_page, "city1.gov")
- self.assertContains(review_page, "For all kinds of things.")
- self.assertContains(review_page, "Testy you")
- self.assertContains(review_page, "Tester you")
- self.assertContains(review_page, "Admin Tester")
- self.assertContains(review_page, "testy-admin@town.com")
- self.assertContains(review_page, "(201) 555-5556")
- self.assertContains(review_page, "Testy2")
- self.assertContains(review_page, "Tester2")
- self.assertContains(review_page, "Another Tester")
- self.assertContains(review_page, "testy2@town.com")
- self.assertContains(review_page, "(201) 555-5557")
- self.assertContains(review_page, "Nothing else.")
-
- # We can't test the modal itself as it relies on JS for init and triggering,
- # but we can test for the existence of its trigger:
- self.assertContains(review_page, "toggle-submit-domain-request")
- # And the existence of the modal's data parked and ready for the js init.
- # The next assert also tests for the passed requested domain context from
- # the view > application_form > modal
- self.assertContains(review_page, "You are about to submit a domain request for city.gov")
-
- # final submission results in a redirect to the "finished" URL
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- with less_console_noise():
- review_result = review_form.submit()
-
- self.assertEqual(review_result.status_code, 302)
- self.assertEqual(review_result["Location"], "/request/finished/")
- num_pages_tested += 1
-
- # following this redirect is a GET request, so include the cookie
- # here too.
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- with less_console_noise():
- final_result = review_result.follow()
- self.assertContains(final_result, "Thanks for your domain request!")
-
- # check that any new pages are added to this test
- self.assertEqual(num_pages, num_pages_tested)
-
- # This is the start of a test to check an existing application, it currently
- # does not work and results in errors as noted in:
- # https://github.com/cisagov/getgov/pull/728
- @skip("WIP")
- def test_application_form_started_allsteps(self):
- num_pages_tested = 0
- # elections, type_of_work, tribal_government
- SKIPPED_PAGES = 3
- DASHBOARD_PAGE = 1
- num_pages = len(self.TITLES) - SKIPPED_PAGES + DASHBOARD_PAGE
-
- application = completed_application(user=self.user)
- application.save()
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- self.assertContains(home_page, "Started")
- num_pages_tested += 1
-
- # TODO: For some reason this click results in a new application being generated
- # This appraoch is an alternatie to using get as is being done below
- #
- # type_page = home_page.click("Edit")
-
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- url = reverse("edit-application", kwargs={"id": application.pk})
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # TODO: The following line results in a django error on middleware
- response = self.client.get(url, follow=True)
- self.assertContains(response, "Type of organization")
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # TODO: Step through the remaining pages
-
- self.assertEqual(num_pages, num_pages_tested)
-
- def test_application_form_conditional_federal(self):
- """Federal branch question is shown for federal organizations."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # ---- TYPE PAGE ----
-
- # the conditional step titles shouldn't appear initially
- self.assertNotContains(type_page, self.TITLES["organization_federal"])
- self.assertNotContains(type_page, self.TITLES["organization_election"])
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "federal"
-
- # set the session ID before .submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # the post request should return a redirect to the federal branch
- # question
- self.assertEqual(type_result.status_code, 302)
- self.assertEqual(type_result["Location"], "/request/organization_federal/")
-
- # and the step label should appear in the sidebar of the resulting page
- # but the step label for the elections page should not appear
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_page = type_result.follow()
- self.assertContains(federal_page, self.TITLES["organization_federal"])
- self.assertNotContains(federal_page, self.TITLES["organization_election"])
-
- # continuing on in the flow we need to see top-level agency on the
- # contact page
- federal_page.forms[0]["organization_federal-federal_type"] = "executive"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_result = federal_page.forms[0].submit()
- # the post request should return a redirect to the contact
- # question
- self.assertEqual(federal_result.status_code, 302)
- self.assertEqual(federal_result["Location"], "/request/organization_contact/")
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_page = federal_result.follow()
- self.assertContains(contact_page, "Federal agency")
-
- def test_application_form_conditional_elections(self):
- """Election question is shown for other organizations."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # ---- TYPE PAGE ----
-
- # the conditional step titles shouldn't appear initially
- self.assertNotContains(type_page, self.TITLES["organization_federal"])
- self.assertNotContains(type_page, self.TITLES["organization_election"])
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "county"
-
- # set the session ID before .submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # the post request should return a redirect to the elections question
- self.assertEqual(type_result.status_code, 302)
- self.assertEqual(type_result["Location"], "/request/organization_election/")
-
- # and the step label should appear in the sidebar of the resulting page
- # but the step label for the elections page should not appear
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- election_page = type_result.follow()
- self.assertContains(election_page, self.TITLES["organization_election"])
- self.assertNotContains(election_page, self.TITLES["organization_federal"])
-
- # continuing on in the flow we need to NOT see top-level agency on the
- # contact page
- election_page.forms[0]["organization_election-is_election_board"] = "True"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- election_result = election_page.forms[0].submit()
- # the post request should return a redirect to the contact
- # question
- self.assertEqual(election_result.status_code, 302)
- self.assertEqual(election_result["Location"], "/request/organization_contact/")
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_page = election_result.follow()
- self.assertNotContains(contact_page, "Federal agency")
-
- def test_application_form_section_skipping(self):
- """Can skip forward and back in sections"""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "federal"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_page = type_result.follow()
-
- # Now on federal type page, click back to the organization type
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- new_page = federal_page.click(str(self.TITLES["organization_type"]), index=0)
-
- # Should be a link to the organization_federal page
- self.assertGreater(
- len(new_page.html.find_all("a", href="/request/organization_federal/")),
- 0,
- )
-
- def test_application_form_nonfederal(self):
- """Non-federal organizations don't have to provide their federal agency."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_page = type_result.follow()
- org_contact_form = contact_page.forms[0]
-
- self.assertNotIn("federal_agency", org_contact_form.fields)
-
- # minimal fields that must be filled out
- org_contact_form["organization_contact-organization_name"] = "Testorg"
- org_contact_form["organization_contact-address_line1"] = "address 1"
- org_contact_form["organization_contact-city"] = "NYC"
- org_contact_form["organization_contact-state_territory"] = "NY"
- org_contact_form["organization_contact-zipcode"] = "10002"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_result = org_contact_form.submit()
-
- # the post request should return a redirect to the
- # about your organization page if it was successful.
- self.assertEqual(contact_result.status_code, 302)
- self.assertEqual(contact_result["Location"], "/request/about_your_organization/")
-
- def test_application_about_your_organization_special(self):
- """Special districts have to answer an additional question."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_page.forms[0].submit()
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_page = type_result.follow()
-
- self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION])
-
- def test_yes_no_form_inits_blank_for_new_application(self):
- """On the Other Contacts page, the yes/no form gets initialized with nothing selected for
- new applications"""
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None)
-
- def test_yes_no_form_inits_yes_for_application_with_other_contacts(self):
- """On the Other Contacts page, the yes/no form gets initialized with YES selected if the
- application has other contacts"""
- # Application has other contacts by default
- application = completed_application(user=self.user)
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
-
- def test_yes_no_form_inits_no_for_application_with_no_other_contacts_rationale(self):
- """On the Other Contacts page, the yes/no form gets initialized with NO selected if the
- application has no other contacts"""
- # Application has other contacts by default
- application = completed_application(user=self.user, has_other_contacts=False)
- application.no_other_contacts_rationale = "Hello!"
- application.save()
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False")
-
- def test_submitting_other_contacts_deletes_no_other_contacts_rationale(self):
- """When a user submits the Other Contacts form with other contacts selected, the application's
- no other contacts rationale gets deleted"""
- # Application has other contacts by default
- application = completed_application(user=self.user, has_other_contacts=False)
- application.no_other_contacts_rationale = "Hello!"
- application.save()
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False")
-
- other_contacts_form["other_contacts-has_other_contacts"] = "True"
-
- other_contacts_form["other_contacts-0-first_name"] = "Testy"
- other_contacts_form["other_contacts-0-middle_name"] = ""
- other_contacts_form["other_contacts-0-last_name"] = "McTesterson"
- other_contacts_form["other_contacts-0-title"] = "Lord"
- other_contacts_form["other_contacts-0-email"] = "testy@abc.org"
- other_contacts_form["other_contacts-0-phone"] = "(201) 555-0123"
-
- # Submit the now empty form
- other_contacts_form.submit()
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database
- application = DomainApplication.objects.get()
- self.assertEqual(
- application.other_contacts.count(),
- 1,
- )
-
- self.assertEquals(
- application.no_other_contacts_rationale,
- None,
- )
-
- def test_submitting_no_other_contacts_rationale_deletes_other_contacts(self):
- """When a user submits the Other Contacts form with no other contacts selected, the application's
- other contacts get deleted for other contacts that exist and are not joined to other objects
- """
- # Application has other contacts by default
- application = completed_application(user=self.user)
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
-
- other_contacts_form["other_contacts-has_other_contacts"] = "False"
-
- other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!"
-
- # Submit the now empty form
- other_contacts_form.submit()
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database
- application = DomainApplication.objects.get()
- self.assertEqual(
- application.other_contacts.count(),
- 0,
- )
-
- self.assertEquals(
- application.no_other_contacts_rationale,
- "Hello again!",
- )
-
- def test_submitting_no_other_contacts_rationale_removes_reference_other_contacts_when_joined(self):
- """When a user submits the Other Contacts form with no other contacts selected, the application's
- other contacts references get removed for other contacts that exist and are joined to other objects"""
- # Populate the database with a domain application that
- # has 1 "other contact" assigned to it
- # We'll do it from scratch so we can reuse the other contact
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(555) 555 5555",
- )
- 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",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(other)
-
- # Now let's join the other contact to another object
- domain_info = DomainInformation.objects.create(creator=self.user)
- domain_info.other_contacts.set([other])
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
- self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
-
- other_contacts_form["other_contacts-has_other_contacts"] = "False"
-
- other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!"
-
- # Submit the now empty form
- other_contacts_form.submit()
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application
- application = DomainApplication.objects.get()
- self.assertEqual(
- application.other_contacts.count(),
- 0,
- )
-
- # Verify that the 'other' contact object still exists
- domain_info = DomainInformation.objects.get()
- self.assertEqual(
- domain_info.other_contacts.count(),
- 1,
- )
- self.assertEqual(
- domain_info.other_contacts.all()[0].first_name,
- "Testy2",
- )
-
- self.assertEquals(
- application.no_other_contacts_rationale,
- "Hello again!",
- )
-
- def test_if_yes_no_form_is_no_then_no_other_contacts_required(self):
- """Applicants with no other contacts have to give a reason."""
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- other_contacts_form = other_contacts_page.forms[0]
- other_contacts_form["other_contacts-has_other_contacts"] = "False"
- response = other_contacts_page.forms[0].submit()
-
- # The textarea for no other contacts returns this error message
- # Assert that it is returned, ie the no other contacts form is required
- self.assertContains(response, "Rationale for no other employees is required.")
-
- # The first name field for other contacts returns this error message
- # Assert that it is not returned, ie the contacts form is not required
- self.assertNotContains(response, "Enter the first name / given name of this contact.")
-
- def test_if_yes_no_form_is_yes_then_other_contacts_required(self):
- """Applicants with other contacts do not have to give a reason."""
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- other_contacts_form = other_contacts_page.forms[0]
- other_contacts_form["other_contacts-has_other_contacts"] = "True"
- response = other_contacts_page.forms[0].submit()
-
- # The textarea for no other contacts returns this error message
- # Assert that it is not returned, ie the no other contacts form is not required
- self.assertNotContains(response, "Rationale for no other employees is required.")
-
- # The first name field for other contacts returns this error message
- # Assert that it is returned, ie the contacts form is required
- self.assertContains(response, "Enter the first name / given name of this contact.")
-
- def test_delete_other_contact(self):
- """Other contacts can be deleted after being saved to database.
-
- This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application,
- loading the form and marking one contact up for deletion."""
- # Populate the database with a domain application that
- # has 2 "other contact" assigned to it
- # We'll do it from scratch so we can reuse the other contact
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- you, _ = Contact.objects.get_or_create(
- first_name="Testy you",
- last_name="Tester you",
- title="Admin Tester",
- email="testy-admin@town.com",
- phone="(201) 555 5556",
- )
- other, _ = Contact.objects.get_or_create(
- first_name="Testy2",
- last_name="Tester2",
- title="Another Tester",
- email="testy2@town.com",
- phone="(201) 555 5557",
- )
- other2, _ = Contact.objects.get_or_create(
- first_name="Testy3",
- last_name="Tester3",
- title="Another Tester",
- email="testy3@town.com",
- phone="(201) 555 5557",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(other)
- application.other_contacts.add(other2)
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
-
- # Minimal check to ensure the form is loaded with both other contacts
- self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
- self.assertEqual(other_contacts_form["other_contacts-1-first_name"].value, "Testy3")
-
- # Mark the first dude for deletion
- other_contacts_form.set("other_contacts-0-DELETE", "on")
-
- # Submit the form
- other_contacts_form.submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # Verify that the first dude was deleted
- application = DomainApplication.objects.get()
- self.assertEqual(application.other_contacts.count(), 1)
- self.assertEqual(application.other_contacts.first().first_name, "Testy3")
-
- def test_delete_other_contact_does_not_allow_zero_contacts(self):
- """Delete Other Contact does not allow submission with zero contacts."""
- # Populate the database with a domain application that
- # has 1 "other contact" assigned to it
- # We'll do it from scratch so we can reuse the other contact
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- you, _ = Contact.objects.get_or_create(
- first_name="Testy you",
- last_name="Tester you",
- title="Admin Tester",
- email="testy-admin@town.com",
- phone="(201) 555 5556",
- )
- other, _ = Contact.objects.get_or_create(
- first_name="Testy2",
- last_name="Tester2",
- title="Another Tester",
- email="testy2@town.com",
- phone="(201) 555 5557",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(other)
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
-
- # Mark the first dude for deletion
- other_contacts_form.set("other_contacts-0-DELETE", "on")
-
- # Submit the form
- other_contacts_form.submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- # Verify that the contact was not deleted
- application = DomainApplication.objects.get()
- self.assertEqual(application.other_contacts.count(), 1)
- self.assertEqual(application.other_contacts.first().first_name, "Testy2")
-
- def test_delete_other_contact_sets_visible_empty_form_as_required_after_failed_submit(self):
- """When you:
- 1. add an empty contact,
- 2. delete existing contacts,
- 3. then submit,
- The forms on page reload shows all the required fields and their errors."""
-
- # Populate the database with a domain application that
- # has 1 "other contact" assigned to it
- # We'll do it from scratch so we can reuse the other contact
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- you, _ = Contact.objects.get_or_create(
- first_name="Testy you",
- last_name="Tester you",
- title="Admin Tester",
- email="testy-admin@town.com",
- phone="(201) 555 5556",
- )
- other, _ = Contact.objects.get_or_create(
- first_name="Testy2",
- last_name="Tester2",
- title="Another Tester",
- email="testy2@town.com",
- phone="(201) 555 5557",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(other)
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
-
- # Set total forms to 2 indicating an additional formset was added.
- # Submit no data though for the second formset.
- # Set the first formset to be deleted.
- other_contacts_form["other_contacts-TOTAL_FORMS"] = "2"
- other_contacts_form.set("other_contacts-0-DELETE", "on")
-
- response = other_contacts_form.submit()
-
- # Assert that the response presents errors to the user, including to
- # Enter the first name ...
- self.assertContains(response, "Enter the first name / given name of this contact.")
-
- def test_edit_other_contact_in_place(self):
- """When you:
- 1. edit an existing contact which is not joined to another model,
- 2. then submit,
- The application is linked to the existing contact, and the existing contact updated."""
-
- # Populate the database with a domain application that
- # has 1 "other contact" assigned to it
- # We'll do it from scratch
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- you, _ = Contact.objects.get_or_create(
- first_name="Testy you",
- last_name="Tester you",
- title="Admin Tester",
- email="testy-admin@town.com",
- phone="(201) 555 5556",
- )
- other, _ = Contact.objects.get_or_create(
- first_name="Testy2",
- last_name="Tester2",
- title="Another Tester",
- email="testy2@town.com",
- phone="(201) 555 5557",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(other)
-
- # other_contact_pk is the initial pk of the other contact. set it before update
- # to be able to verify after update that the same contact object is in place
- other_contact_pk = other.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
-
- # update the first name of the contact
- other_contacts_form["other_contacts-0-first_name"] = "Testy3"
-
- # Submit the updated form
- other_contacts_form.submit()
-
- application.refresh_from_db()
-
- # assert that the Other Contact is updated "in place"
- other_contact = application.other_contacts.all()[0]
- self.assertEquals(other_contact_pk, other_contact.id)
- self.assertEquals("Testy3", other_contact.first_name)
-
- def test_edit_other_contact_creates_new(self):
- """When you:
- 1. edit an existing contact which IS joined to another model,
- 2. then submit,
- The application is linked to a new contact, and the new contact is updated."""
-
- # Populate the database with a domain application that
- # has 1 "other contact" assigned to it, the other contact is also
- # the authorizing official initially
- # We'll do it from scratch
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- you, _ = Contact.objects.get_or_create(
- first_name="Testy you",
- last_name="Tester you",
- title="Admin Tester",
- email="testy-admin@town.com",
- phone="(201) 555 5556",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- submitter=you,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(ao)
-
- # other_contact_pk is the initial pk of the other contact. set it before update
- # to be able to verify after update that the ao contact is still in place
- # and not updated, and that the new contact has a new id
- other_contact_pk = ao.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_page = self.app.get(reverse("application:other_contacts"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- other_contacts_form = other_contacts_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy")
-
- # update the first name of the contact
- other_contacts_form["other_contacts-0-first_name"] = "Testy2"
-
- # Submit the updated form
- other_contacts_form.submit()
-
- application.refresh_from_db()
-
- # assert that other contact info is updated, and that a new Contact
- # is created for the other contact
- other_contact = application.other_contacts.all()[0]
- self.assertNotEquals(other_contact_pk, other_contact.id)
- self.assertEquals("Testy2", other_contact.first_name)
- # assert that the authorizing official is not updated
- authorizing_official = application.authorizing_official
- self.assertEquals("Testy", authorizing_official.first_name)
-
- def test_edit_authorizing_official_in_place(self):
- """When you:
- 1. edit an authorizing official which is not joined to another model,
- 2. then submit,
- The application is linked to the existing ao, and the ao updated."""
-
- # Populate the database with a domain application that
- # has an authorizing_official (ao)
- # We'll do it from scratch
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- creator=self.user,
- status="started",
- )
-
- # ao_pk is the initial pk of the Authorizing Official. set it before update
- # to be able to verify after update that the same Contact object is in place
- ao_pk = ao.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- ao_page = self.app.get(reverse("application:authorizing_official"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- ao_form = ao_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy")
-
- # update the first name of the contact
- ao_form["authorizing_official-first_name"] = "Testy2"
-
- # Submit the updated form
- ao_form.submit()
-
- application.refresh_from_db()
-
- # assert AO is updated "in place"
- updated_ao = application.authorizing_official
- self.assertEquals(ao_pk, updated_ao.id)
- self.assertEquals("Testy2", updated_ao.first_name)
-
- def test_edit_authorizing_official_creates_new(self):
- """When you:
- 1. edit an existing authorizing official which IS joined to another model,
- 2. then submit,
- The application is linked to a new Contact, and the new Contact is updated."""
-
- # Populate the database with a domain application that
- # has authorizing official assigned to it, the authorizing offical is also
- # an other contact initially
- # We'll do it from scratch
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(ao)
-
- # ao_pk is the initial pk of the authorizing official. set it before update
- # to be able to verify after update that the other contact is still in place
- # and not updated, and that the new ao has a new id
- ao_pk = ao.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- ao_page = self.app.get(reverse("application:authorizing_official"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- ao_form = ao_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy")
-
- # update the first name of the contact
- ao_form["authorizing_official-first_name"] = "Testy2"
-
- # Submit the updated form
- ao_form.submit()
-
- application.refresh_from_db()
-
- # assert that the other contact is not updated
- other_contacts = application.other_contacts.all()
- other_contact = other_contacts[0]
- self.assertEquals(ao_pk, other_contact.id)
- self.assertEquals("Testy", other_contact.first_name)
- # assert that the authorizing official is updated
- authorizing_official = application.authorizing_official
- self.assertEquals("Testy2", authorizing_official.first_name)
-
- def test_edit_submitter_in_place(self):
- """When you:
- 1. edit a submitter (your contact) which is not joined to another model,
- 2. then submit,
- The application is linked to the existing submitter, and the submitter updated."""
-
- # Populate the database with a domain application that
- # has a submitter
- # We'll do it from scratch
- you, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- submitter=you,
- creator=self.user,
- status="started",
- )
-
- # submitter_pk is the initial pk of the submitter. set it before update
- # to be able to verify after update that the same contact object is in place
- submitter_pk = you.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- your_contact_page = self.app.get(reverse("application:your_contact"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- your_contact_form = your_contact_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy")
-
- # update the first name of the contact
- your_contact_form["your_contact-first_name"] = "Testy2"
-
- # Submit the updated form
- your_contact_form.submit()
-
- application.refresh_from_db()
-
- updated_submitter = application.submitter
- self.assertEquals(submitter_pk, updated_submitter.id)
- self.assertEquals("Testy2", updated_submitter.first_name)
-
- def test_edit_submitter_creates_new(self):
- """When you:
- 1. edit an existing your contact which IS joined to another model,
- 2. then submit,
- The application is linked to a new Contact, and the new Contact is updated."""
-
- # Populate the database with a domain application that
- # has submitter assigned to it, the submitter is also
- # an other contact initially
- # We'll do it from scratch
- submitter, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(201) 555 5555",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- submitter=submitter,
- creator=self.user,
- status="started",
- )
- application.other_contacts.add(submitter)
-
- # submitter_pk is the initial pk of the your contact. set it before update
- # to be able to verify after update that the other contact is still in place
- # and not updated, and that the new submitter has a new id
- submitter_pk = submitter.id
-
- # prime the form by visiting /edit
- self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- your_contact_page = self.app.get(reverse("application:your_contact"))
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- your_contact_form = your_contact_page.forms[0]
-
- # Minimal check to ensure the form is loaded
- self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy")
-
- # update the first name of the contact
- your_contact_form["your_contact-first_name"] = "Testy2"
-
- # Submit the updated form
- your_contact_form.submit()
-
- application.refresh_from_db()
-
- # assert that the other contact is not updated
- other_contacts = application.other_contacts.all()
- other_contact = other_contacts[0]
- self.assertEquals(submitter_pk, other_contact.id)
- self.assertEquals("Testy", other_contact.first_name)
- # assert that the submitter is updated
- submitter = application.submitter
- self.assertEquals("Testy2", submitter.first_name)
-
- def test_application_about_your_organiztion_interstate(self):
- """Special districts have to answer an additional question."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- contact_page = type_result.follow()
-
- self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION])
-
- def test_application_tribal_government(self):
- """Tribal organizations have to answer an additional question."""
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.TRIBAL
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
- # the tribal government page comes immediately afterwards
- self.assertIn("/tribal_government", type_result.headers["Location"])
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- tribal_government_page = type_result.follow()
-
- # and the step is on the sidebar list.
- self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT])
-
- def test_application_ao_dynamic_text(self):
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # ---- TYPE PAGE ----
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "federal"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # ---- FEDERAL BRANCH PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_page = type_result.follow()
- federal_form = federal_page.forms[0]
- federal_form["organization_federal-federal_type"] = "executive"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_result = federal_form.submit()
-
- # ---- ORG CONTACT PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_page = federal_result.follow()
- org_contact_form = org_contact_page.forms[0]
- # federal agency so we have to fill in federal_agency
- org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
- org_contact_form["organization_contact-organization_name"] = "Testorg"
- org_contact_form["organization_contact-address_line1"] = "address 1"
- org_contact_form["organization_contact-address_line2"] = "address 2"
- org_contact_form["organization_contact-city"] = "NYC"
- org_contact_form["organization_contact-state_territory"] = "NY"
- org_contact_form["organization_contact-zipcode"] = "10002"
- org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_result = org_contact_form.submit()
-
- # ---- AO CONTACT PAGE ----
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page = org_contact_result.follow()
- self.assertContains(ao_page, "Executive branch federal agencies")
-
- # Go back to organization type page and change type
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page.click(str(self.TITLES["organization_type"]), index=0)
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_form["organization_type-organization_type"] = "city"
- type_result = type_form.submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- election_page = type_result.follow()
-
- # Go back to AO page and test the dynamic text changed
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page = election_page.click(str(self.TITLES["authorizing_official"]), index=0)
- self.assertContains(ao_page, "Domain requests from cities")
-
- def test_application_dotgov_domain_dynamic_text(self):
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- # ---- TYPE PAGE ----
- type_form = type_page.forms[0]
- type_form["organization_type-organization_type"] = "federal"
-
- # test next button
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_result = type_form.submit()
-
- # ---- FEDERAL BRANCH PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_page = type_result.follow()
- federal_form = federal_page.forms[0]
- federal_form["organization_federal-federal_type"] = "executive"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- federal_result = federal_form.submit()
-
- # ---- ORG CONTACT PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_page = federal_result.follow()
- org_contact_form = org_contact_page.forms[0]
- # federal agency so we have to fill in federal_agency
- org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
- org_contact_form["organization_contact-organization_name"] = "Testorg"
- org_contact_form["organization_contact-address_line1"] = "address 1"
- org_contact_form["organization_contact-address_line2"] = "address 2"
- org_contact_form["organization_contact-city"] = "NYC"
- org_contact_form["organization_contact-state_territory"] = "NY"
- org_contact_form["organization_contact-zipcode"] = "10002"
- org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- org_contact_result = org_contact_form.submit()
-
- # ---- AO CONTACT PAGE ----
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page = org_contact_result.follow()
-
- # ---- AUTHORIZING OFFICIAL PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_page = org_contact_result.follow()
- ao_form = ao_page.forms[0]
- ao_form["authorizing_official-first_name"] = "Testy ATO"
- ao_form["authorizing_official-last_name"] = "Tester ATO"
- ao_form["authorizing_official-title"] = "Chief Tester"
- ao_form["authorizing_official-email"] = "testy@town.com"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_result = ao_form.submit()
-
- # ---- CURRENT SITES PAGE ----
- # Follow the redirect to the next form page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_page = ao_result.follow()
- current_sites_form = current_sites_page.forms[0]
- current_sites_form["current_sites-0-website"] = "www.city.com"
-
- # test saving the page
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_result = current_sites_form.submit()
-
- # ---- DOTGOV DOMAIN PAGE ----
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- dotgov_page = current_sites_result.follow()
-
- self.assertContains(dotgov_page, "medicare.gov")
-
- # Go back to organization type page and change type
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- dotgov_page.click(str(self.TITLES["organization_type"]), index=0)
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_form["organization_type-organization_type"] = "city"
- type_result = type_form.submit()
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- election_page = type_result.follow()
-
- # Go back to dotgov domain page to test the dynamic text changed
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- dotgov_page = election_page.click(str(self.TITLES["dotgov_domain"]), index=0)
- self.assertContains(dotgov_page, "CityofEudoraKS.gov")
- self.assertNotContains(dotgov_page, "medicare.gov")
-
- def test_application_formsets(self):
- """Users are able to add more than one of some fields."""
- current_sites_page = self.app.get(reverse("application:current_sites"))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- # fill in the form field
- current_sites_form = current_sites_page.forms[0]
- self.assertIn("current_sites-0-website", current_sites_form.fields)
- self.assertNotIn("current_sites-1-website", current_sites_form.fields)
- current_sites_form["current_sites-0-website"] = "https://example.com"
-
- # click "Add another"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_result = current_sites_form.submit("submit_button", value="save")
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- current_sites_form = current_sites_result.follow().forms[0]
-
- # verify that there are two form fields
- value = current_sites_form["current_sites-0-website"].value
- self.assertEqual(value, "https://example.com")
- self.assertIn("current_sites-1-website", current_sites_form.fields)
- # and it is correctly referenced in the ManyToOne relationship
- application = DomainApplication.objects.get() # there's only one
- self.assertEqual(
- application.current_websites.filter(website="https://example.com").count(),
- 1,
- )
-
- @skip("WIP")
- def test_application_edit_restore(self):
- """
- Test that a previously saved application is available at the /edit endpoint.
- """
- ao, _ = Contact.objects.get_or_create(
- first_name="Testy",
- last_name="Tester",
- title="Chief Tester",
- email="testy@town.com",
- phone="(555) 555 5555",
- )
- domain, _ = Domain.objects.get_or_create(name="city.gov")
- alt, _ = Website.objects.get_or_create(website="city1.gov")
- current, _ = Website.objects.get_or_create(website="city.com")
- 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",
- )
- application, _ = DomainApplication.objects.get_or_create(
- organization_type="federal",
- federal_type="executive",
- purpose="Purpose of the site",
- anything_else="No",
- is_policy_acknowledged=True,
- organization_name="Testorg",
- address_line1="address 1",
- state_territory="NY",
- zipcode="10002",
- authorizing_official=ao,
- requested_domain=domain,
- submitter=you,
- creator=self.user,
- )
- application.other_contacts.add(other)
- application.current_websites.add(current)
- application.alternative_domains.add(alt)
-
- # prime the form by visiting /edit
- url = reverse("edit-application", kwargs={"id": application.pk})
- response = self.client.get(url)
-
- # TODO: this is a sketch of each page in the wizard which needs to be tested
- # Django does not have tools sufficient for real end to end integration testing
- # (for example, USWDS moves radio buttons off screen and replaces them with
- # CSS styled "fakes" -- Django cannot determine if those are visually correct)
- # -- the best that can/should be done here is to ensure the correct values
- # are being passed to the templating engine
-
- url = reverse("application:organization_type")
- response = self.client.get(url, follow=True)
- self.assertContains(response, "
")
- # choices = response.context['wizard']['form']['organization_type'].subwidgets
- # radio = [ x for x in choices if x.data["value"] == "federal" ][0]
- # checked = radio.data["selected"]
- # self.assertTrue(checked)
-
- # url = reverse("application:organization_federal")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:organization_contact")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:authorizing_official")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:current_sites")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:dotgov_domain")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:purpose")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:your_contact")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:other_contacts")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:other_contacts")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:security_email")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:anything_else")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- # url = reverse("application:requirements")
- # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # page = self.app.get(url)
- # self.assertNotContains(page, "VALUE")
-
- def test_long_org_name_in_application(self):
- """
- Make sure the long name is displaying in the application form,
- org step
- """
- intro_page = self.app.get(reverse("application:"))
- # django-webtest does not handle cookie-based sessions well because it keeps
- # resetting the session key on each new request, thus destroying the concept
- # of a "session". We are going to do it manually, saving the session ID here
- # and then setting the cookie on each request.
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- intro_form = intro_page.forms[0]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- intro_result = intro_form.submit()
-
- # follow first redirect
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- type_page = intro_result.follow()
-
- self.assertContains(type_page, "Federal: an agency of the U.S. government")
-
- def test_submit_modal_no_domain_text_fallback(self):
- """When user clicks on submit your domain request and the requested domain
- is null (possible through url direct access to the review page), present
- fallback copy in the modal's header.
-
- NOTE: This may be a moot point if we implement a more solid pattern in the
- future, like not a submit action at all on the review page."""
-
- review_page = self.app.get(reverse("application:review"))
- self.assertContains(review_page, "toggle-submit-domain-request")
- self.assertContains(review_page, "You are about to submit an incomplete request")
-
-
-class TestWithDomainPermissions(TestWithUser):
- def setUp(self):
- super().setUp()
- self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- self.domain_with_ip, _ = Domain.objects.get_or_create(name="nameserverwithip.gov")
- self.domain_just_nameserver, _ = Domain.objects.get_or_create(name="justnameserver.com")
- self.domain_no_information, _ = Domain.objects.get_or_create(name="noinformation.gov")
- self.domain_on_hold, _ = Domain.objects.get_or_create(
- name="on-hold.gov",
- state=Domain.State.ON_HOLD,
- expiration_date=timezone.make_aware(
- datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
- ),
- )
- self.domain_deleted, _ = Domain.objects.get_or_create(
- name="deleted.gov",
- state=Domain.State.DELETED,
- expiration_date=timezone.make_aware(
- datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
- ),
- )
-
- self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
- # We could simply use domain (igorville) but this will be more readable in tests
- # that inherit this setUp
- self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov")
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dsdata)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_multdsdata)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dnssec_none)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_with_ip)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_just_nameserver)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_on_hold)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_deleted)
-
- self.role, _ = UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
- )
-
- UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.MANAGER
- )
- UserDomainRole.objects.get_or_create(
- user=self.user,
- domain=self.domain_multdsdata,
- role=UserDomainRole.Roles.MANAGER,
- )
- UserDomainRole.objects.get_or_create(
- user=self.user,
- domain=self.domain_dnssec_none,
- role=UserDomainRole.Roles.MANAGER,
- )
- UserDomainRole.objects.get_or_create(
- user=self.user,
- domain=self.domain_with_ip,
- role=UserDomainRole.Roles.MANAGER,
- )
- UserDomainRole.objects.get_or_create(
- user=self.user,
- domain=self.domain_just_nameserver,
- role=UserDomainRole.Roles.MANAGER,
- )
- UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain_on_hold, role=UserDomainRole.Roles.MANAGER
- )
- UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain_deleted, role=UserDomainRole.Roles.MANAGER
- )
-
- def tearDown(self):
- try:
- UserDomainRole.objects.all().delete()
- if hasattr(self.domain, "contacts"):
- self.domain.contacts.all().delete()
- DomainApplication.objects.all().delete()
- DomainInformation.objects.all().delete()
- PublicContact.objects.all().delete()
- HostIP.objects.all().delete()
- Host.objects.all().delete()
- Domain.objects.all().delete()
- UserDomainRole.objects.all().delete()
- except ValueError: # pass if already deleted
- pass
- super().tearDown()
-
-
-class TestDomainPermissions(TestWithDomainPermissions):
- def test_not_logged_in(self):
- """Not logged in gets a redirect to Login."""
- for view_name in [
- "domain",
- "domain-users",
- "domain-users-add",
- "domain-dns-nameservers",
- "domain-org-name-address",
- "domain-authorizing-official",
- "domain-your-contact-information",
- "domain-security-email",
- ]:
- with self.subTest(view_name=view_name):
- response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id}))
- self.assertEqual(response.status_code, 302)
-
- def test_no_domain_role(self):
- """Logged in but no role gets 403 Forbidden."""
- self.client.force_login(self.user)
- self.role.delete() # user no longer has a role on this domain
-
- for view_name in [
- "domain",
- "domain-users",
- "domain-users-add",
- "domain-dns-nameservers",
- "domain-org-name-address",
- "domain-authorizing-official",
- "domain-your-contact-information",
- "domain-security-email",
- ]:
- with self.subTest(view_name=view_name):
- with less_console_noise():
- response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id}))
- self.assertEqual(response.status_code, 403)
-
- def test_domain_pages_blocked_for_on_hold_and_deleted(self):
- """Test that the domain pages are blocked for on hold and deleted domains"""
-
- self.client.force_login(self.user)
- for view_name in [
- "domain-users",
- "domain-users-add",
- "domain-dns",
- "domain-dns-nameservers",
- "domain-dns-dnssec",
- "domain-dns-dnssec-dsdata",
- "domain-org-name-address",
- "domain-authorizing-official",
- "domain-your-contact-information",
- "domain-security-email",
- ]:
- for domain in [
- self.domain_on_hold,
- self.domain_deleted,
- ]:
- with self.subTest(view_name=view_name, domain=domain):
- with less_console_noise():
- response = self.client.get(reverse(view_name, kwargs={"pk": domain.id}))
- self.assertEqual(response.status_code, 403)
-
-
-class TestDomainOverview(TestWithDomainPermissions, WebTest):
- def setUp(self):
- super().setUp()
- self.app.set_user(self.user.username)
- self.client.force_login(self.user)
-
-
-class TestDomainDetail(TestDomainOverview):
- @skip("Assertion broke for no reason, why? Need to fix")
- def test_domain_detail_link_works(self):
- home_page = self.app.get("/")
- logger.info(f"This is the value of home_page: {home_page}")
- self.assertContains(home_page, "igorville.gov")
- # click the "Edit" link
- detail_page = home_page.click("Manage", index=0)
- self.assertContains(detail_page, "igorville.gov")
- self.assertContains(detail_page, "Status")
-
- def test_unknown_domain_does_not_show_as_expired_on_homepage(self):
- """An UNKNOWN domain does not show as expired on the homepage.
- It shows as 'DNS needed'"""
- # At the time of this test's writing, there are 6 UNKNOWN domains inherited
- # from constructors. Let's reset.
- Domain.objects.all().delete()
- UserDomainRole.objects.all().delete()
- self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- home_page = self.app.get("/")
- self.assertNotContains(home_page, "igorville.gov")
- self.role, _ = UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
- )
- home_page = self.app.get("/")
- self.assertContains(home_page, "igorville.gov")
- igorville = Domain.objects.get(name="igorville.gov")
- self.assertEquals(igorville.state, Domain.State.UNKNOWN)
- self.assertNotContains(home_page, "Expired")
- self.assertContains(home_page, "DNS needed")
-
- def test_unknown_domain_does_not_show_as_expired_on_detail_page(self):
- """An UNKNOWN domain does not show as expired on the detail page.
- It shows as 'DNS needed'"""
- # At the time of this test's writing, there are 6 UNKNOWN domains inherited
- # from constructors. Let's reset.
- Domain.objects.all().delete()
- UserDomainRole.objects.all().delete()
-
- self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
- self.role, _ = UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
- )
-
- home_page = self.app.get("/")
- self.assertContains(home_page, "igorville.gov")
- igorville = Domain.objects.get(name="igorville.gov")
- self.assertEquals(igorville.state, Domain.State.UNKNOWN)
- detail_page = home_page.click("Manage", index=0)
- self.assertNotContains(detail_page, "Expired")
-
- self.assertContains(detail_page, "DNS needed")
-
- def test_domain_detail_blocked_for_ineligible_user(self):
- """We could easily duplicate this test for all domain management
- views, but a single url test should be solid enough since all domain
- management pages share the same permissions class"""
- self.user.status = User.RESTRICTED
- self.user.save()
- home_page = self.app.get("/")
- self.assertContains(home_page, "igorville.gov")
- with less_console_noise():
- response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
- self.assertEqual(response.status_code, 403)
-
- def test_domain_detail_allowed_for_on_hold(self):
- """Test that the domain overview page displays for on hold domain"""
- home_page = self.app.get("/")
- self.assertContains(home_page, "on-hold.gov")
-
- # View domain overview page
- detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_on_hold.id}))
- self.assertNotContains(detail_page, "Edit")
-
- def test_domain_detail_see_just_nameserver(self):
- home_page = self.app.get("/")
- self.assertContains(home_page, "justnameserver.com")
-
- # View nameserver on Domain Overview page
- detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_just_nameserver.id}))
-
- self.assertContains(detail_page, "justnameserver.com")
- self.assertContains(detail_page, "ns1.justnameserver.com")
- self.assertContains(detail_page, "ns2.justnameserver.com")
-
- def test_domain_detail_see_nameserver_and_ip(self):
- home_page = self.app.get("/")
- self.assertContains(home_page, "nameserverwithip.gov")
-
- # View nameserver on Domain Overview page
- detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_with_ip.id}))
-
- self.assertContains(detail_page, "nameserverwithip.gov")
-
- self.assertContains(detail_page, "ns1.nameserverwithip.gov")
- self.assertContains(detail_page, "ns2.nameserverwithip.gov")
- self.assertContains(detail_page, "ns3.nameserverwithip.gov")
- # Splitting IP addresses bc there is odd whitespace and can't strip text
- self.assertContains(detail_page, "(1.2.3.4,")
- self.assertContains(detail_page, "2.3.4.5)")
-
- def test_domain_detail_with_no_information_or_application(self):
- """Test that domain management page returns 200 and displays error
- when no domain information or domain application exist"""
- # have to use staff user for this test
- staff_user = create_user()
- # staff_user.save()
- self.client.force_login(staff_user)
-
- # need to set the analyst_action and analyst_action_location
- # in the session to emulate user clicking Manage Domain
- # in the admin interface
- session = self.client.session
- session["analyst_action"] = "foo"
- session["analyst_action_location"] = self.domain_no_information.id
- session.save()
-
- detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_no_information.id}))
-
- self.assertContains(detail_page, "noinformation.gov")
- self.assertContains(detail_page, "Domain missing domain information")
-
-
-class TestDomainManagers(TestDomainOverview):
- def tearDown(self):
- """Ensure that the user has its original permissions"""
- super().tearDown()
- self.user.is_staff = False
- self.user.save()
-
- def test_domain_managers(self):
- response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id}))
- self.assertContains(response, "Domain managers")
-
- def test_domain_managers_add_link(self):
- """Button to get to user add page works."""
- management_page = self.app.get(reverse("domain-users", kwargs={"pk": self.domain.id}))
- add_page = management_page.click("Add a domain manager")
- self.assertContains(add_page, "Add a domain manager")
-
- def test_domain_user_add(self):
- response = self.client.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- self.assertContains(response, "Add a domain manager")
-
- @boto3_mocking.patching
- def test_domain_user_add_form(self):
- """Adding an existing user works."""
- other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov")
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- add_page.form["email"] = "mayor@igorville.gov"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- success_result = add_page.form.submit()
-
- self.assertEqual(success_result.status_code, 302)
- self.assertEqual(
- success_result["Location"],
- reverse("domain-users", kwargs={"pk": self.domain.id}),
- )
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- success_page = success_result.follow()
- self.assertContains(success_page, "mayor@igorville.gov")
-
- @boto3_mocking.patching
- def test_domain_invitation_created(self):
- """Add user on a nonexistent email creates an invitation.
-
- Adding a non-existent user sends an email as a side-effect, so mock
- out the boto3 SES email sending here.
- """
- # make sure there is no user with this email
- email_address = "mayor@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- success_result = add_page.form.submit()
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- success_page = success_result.follow()
-
- self.assertContains(success_page, email_address)
- self.assertContains(success_page, "Cancel") # link to cancel invitation
- self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists())
-
- @boto3_mocking.patching
- def test_domain_invitation_created_for_caps_email(self):
- """Add user on a nonexistent email with CAPS creates an invitation to lowercase email.
-
- Adding a non-existent user sends an email as a side-effect, so mock
- out the boto3 SES email sending here.
- """
- # make sure there is no user with this email
- email_address = "mayor@igorville.gov"
- caps_email_address = "MAYOR@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = caps_email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- success_result = add_page.form.submit()
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- success_page = success_result.follow()
-
- self.assertContains(success_page, email_address)
- self.assertContains(success_page, "Cancel") # link to cancel invitation
- self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists())
-
- @boto3_mocking.patching
- def test_domain_invitation_email_sent(self):
- """Inviting a non-existent user sends them an email."""
- # make sure there is no user with this email
- email_address = "mayor@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit()
-
- # check the mock instance to see if `send_email` was called right
- mock_client_instance.send_email.assert_called_once_with(
- FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
- Destination={"ToAddresses": [email_address]},
- Content=ANY,
- )
-
- @boto3_mocking.patching
- def test_domain_invitation_email_has_email_as_requestor_non_existent(self):
- """Inviting a non existent user sends them an email, with email as the name."""
- # make sure there is no user with this email
- email_address = "mayor@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
-
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit()
-
- # check the mock instance to see if `send_email` was called right
- mock_client_instance.send_email.assert_called_once_with(
- FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
- Destination={"ToAddresses": [email_address]},
- Content=ANY,
- )
-
- # Check the arguments passed to send_email method
- _, kwargs = mock_client_instance.send_email.call_args
-
- # Extract the email content, and check that the message is as we expect
- email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
- self.assertIn("info@example.com", email_content)
-
- # Check that the requestors first/last name do not exist
- self.assertNotIn("First", email_content)
- self.assertNotIn("Last", email_content)
- self.assertNotIn("First Last", email_content)
-
- @boto3_mocking.patching
- def test_domain_invitation_email_has_email_as_requestor(self):
- """Inviting a user sends them an email, with email as the name."""
- # Create a fake user object
- email_address = "mayor@igorville.gov"
- User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
-
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit()
-
- # check the mock instance to see if `send_email` was called right
- mock_client_instance.send_email.assert_called_once_with(
- FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
- Destination={"ToAddresses": [email_address]},
- Content=ANY,
- )
-
- # Check the arguments passed to send_email method
- _, kwargs = mock_client_instance.send_email.call_args
-
- # Extract the email content, and check that the message is as we expect
- email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
- self.assertIn("info@example.com", email_content)
-
- # Check that the requestors first/last name do not exist
- self.assertNotIn("First", email_content)
- self.assertNotIn("Last", email_content)
- self.assertNotIn("First Last", email_content)
-
- @boto3_mocking.patching
- def test_domain_invitation_email_has_email_as_requestor_staff(self):
- """Inviting a user sends them an email, with email as the name."""
- # Create a fake user object
- email_address = "mayor@igorville.gov"
- User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
-
- # Make sure the user is staff
- self.user.is_staff = True
- self.user.save()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
- mock_client_instance = mock_client.return_value
-
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit()
-
- # check the mock instance to see if `send_email` was called right
- mock_client_instance.send_email.assert_called_once_with(
- FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
- Destination={"ToAddresses": [email_address]},
- Content=ANY,
- )
-
- # Check the arguments passed to send_email method
- _, kwargs = mock_client_instance.send_email.call_args
-
- # Extract the email content, and check that the message is as we expect
- email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
- self.assertIn("help@get.gov", email_content)
-
- # Check that the requestors first/last name do not exist
- self.assertNotIn("First", email_content)
- self.assertNotIn("Last", email_content)
- self.assertNotIn("First Last", email_content)
-
- @boto3_mocking.patching
- def test_domain_invitation_email_displays_error_non_existent(self):
- """Inviting a non existent user sends them an email, with email as the name."""
- # make sure there is no user with this email
- email_address = "mayor@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- # Give the user who is sending the email an invalid email address
- self.user.email = ""
- self.user.save()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
- mock_error_message = MagicMock()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with patch("django.contrib.messages.error") as mock_error_message:
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit().follow()
-
- expected_message_content = "Can't send invitation email. No email is associated with your account."
-
- # Grab the message content
- returned_error_message = mock_error_message.call_args[0][1]
-
- # Check that the message content is what we expect
- self.assertEqual(expected_message_content, returned_error_message)
-
- @boto3_mocking.patching
- def test_domain_invitation_email_displays_error(self):
- """When the requesting user has no email, an error is displayed"""
- # make sure there is no user with this email
- # Create a fake user object
- email_address = "mayor@igorville.gov"
- User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
-
- # Give the user who is sending the email an invalid email address
- self.user.email = ""
- self.user.save()
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- mock_client = MagicMock()
-
- mock_error_message = MagicMock()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with patch("django.contrib.messages.error") as mock_error_message:
- with less_console_noise():
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- add_page.form.submit().follow()
-
- expected_message_content = "Can't send invitation email. No email is associated with your account."
-
- # Grab the message content
- returned_error_message = mock_error_message.call_args[0][1]
-
- # Check that the message content is what we expect
- self.assertEqual(expected_message_content, returned_error_message)
-
- def test_domain_invitation_cancel(self):
- """Posting to the delete view deletes an invitation."""
- email_address = "mayor@igorville.gov"
- invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id}))
- mock_client.EMAILS_SENT.clear()
- with self.assertRaises(DomainInvitation.DoesNotExist):
- DomainInvitation.objects.get(id=invitation.id)
-
- def test_domain_invitation_cancel_no_permissions(self):
- """Posting to the delete view as a different user should fail."""
- email_address = "mayor@igorville.gov"
- invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
-
- other_user = User()
- other_user.save()
- self.client.force_login(other_user)
- mock_client = MagicMock()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise(): # permission denied makes console errors
- result = self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id}))
-
- self.assertEqual(result.status_code, 403)
-
- @boto3_mocking.patching
- def test_domain_invitation_flow(self):
- """Send an invitation to a new user, log in and load the dashboard."""
- email_address = "mayor@igorville.gov"
- User.objects.filter(email=email_address).delete()
-
- add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
-
- self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
-
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- add_page.form["email"] = email_address
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
-
- mock_client = MagicMock()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- add_page.form.submit()
-
- # user was invited, create them
- new_user = User.objects.create(username=email_address, email=email_address)
- # log them in to `self.app`
- self.app.set_user(new_user.username)
- # and manually call the on each login callback
- new_user.on_each_login()
-
- # Now load the home page and make sure our domain appears there
- home_page = self.app.get(reverse("home"))
- self.assertContains(home_page, self.domain.name)
-
-
-class TestDomainNameservers(TestDomainOverview):
- def test_domain_nameservers(self):
- """Can load domain's nameservers page."""
- page = self.client.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "DNS name servers")
-
- def test_domain_nameservers_form_submit_one_nameserver(self):
- """Nameserver form submitted with one nameserver throws error.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form with only one nameserver, should error
- # regarding required fields
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. form requires a minimum of 2 name servers
- self.assertContains(
- result,
- "At least two name servers are required.",
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_subdomain_missing_ip(self):
- """Nameserver form catches missing ip error on subdomain.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-1-server"] = "ns2.igorville.gov"
-
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. subdomain missing an ip
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.MISSING_IP)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_missing_host(self):
- """Nameserver form catches error when host is missing.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-1-ip"] = "127.0.0.1"
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. nameserver has ip but missing host
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.MISSING_HOST)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_duplicate_host(self):
- """Nameserver form catches error when host is duplicated.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form with duplicate host names of fake.host.com
- nameservers_page.form["form-0-ip"] = ""
- nameservers_page.form["form-1-server"] = "fake.host.com"
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. remove duplicate entry
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.DUPLICATE_HOST)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_whitespace(self):
- """Nameserver form removes whitespace from ip.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameserver1 = "ns1.igorville.gov"
- nameserver2 = "ns2.igorville.gov"
- valid_ip = "1.1. 1.1"
- # initial nameservers page has one server with two ips
- # have to throw an error in order to test that the whitespace has been stripped from ip
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without one host and an ip with whitespace
- nameservers_page.form["form-0-server"] = nameserver1
- nameservers_page.form["form-1-ip"] = valid_ip
- nameservers_page.form["form-1-server"] = nameserver2
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an ip address which has been stripped of whitespace,
- # response should be a 302 to success page
- self.assertEqual(result.status_code, 302)
- self.assertEqual(
- result["Location"],
- reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}),
- )
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- page = result.follow()
- # in the event of a generic nameserver error from registry error, there will be a 302
- # with an error message displayed, so need to follow 302 and test for success message
- self.assertContains(page, "The name servers for this domain have been updated")
-
- def test_domain_nameservers_form_submit_glue_record_not_allowed(self):
- """Nameserver form catches error when IP is present
- but host not subdomain.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameserver1 = "ns1.igorville.gov"
- nameserver2 = "ns2.igorville.com"
- valid_ip = "127.0.0.1"
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-0-server"] = nameserver1
- nameservers_page.form["form-1-server"] = nameserver2
- nameservers_page.form["form-1-ip"] = valid_ip
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. nameserver has ip but missing host
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.GLUE_RECORD_NOT_ALLOWED)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_invalid_ip(self):
- """Nameserver form catches invalid IP on submission.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameserver = "ns2.igorville.gov"
- invalid_ip = "123"
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-1-server"] = nameserver
- nameservers_page.form["form-1-ip"] = invalid_ip
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. nameserver has ip but missing host
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.INVALID_IP, nameserver=nameserver)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submit_invalid_host(self):
- """Nameserver form catches invalid host on submission.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameserver = "invalid-nameserver.gov"
- valid_ip = "123.2.45.111"
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-1-server"] = nameserver
- nameservers_page.form["form-1-ip"] = valid_ip
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the required field. nameserver has invalid host
- self.assertContains(
- result,
- str(NameserverError(code=NameserverErrorCodes.INVALID_HOST, nameserver=nameserver)),
- count=2,
- status_code=200,
- )
-
- def test_domain_nameservers_form_submits_successfully(self):
- """Nameserver form submits successfully with valid input.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameserver1 = "ns1.igorville.gov"
- nameserver2 = "ns2.igorville.gov"
- valid_ip = "127.0.0.1"
- # initial nameservers page has one server with two ips
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # attempt to submit the form without two hosts, both subdomains,
- # only one has ips
- nameservers_page.form["form-0-server"] = nameserver1
- nameservers_page.form["form-1-server"] = nameserver2
- nameservers_page.form["form-1-ip"] = valid_ip
- with less_console_noise(): # swallow log warning message
- result = nameservers_page.form.submit()
- # form submission was a successful post, response should be a 302
- self.assertEqual(result.status_code, 302)
- self.assertEqual(
- result["Location"],
- reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}),
- )
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- page = result.follow()
- self.assertContains(page, "The name servers for this domain have been updated")
-
- def test_domain_nameservers_form_invalid(self):
- """Nameserver form does not submit with invalid data.
-
- Uses self.app WebTest because we need to interact with forms.
- """
- nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # first two nameservers are required, so if we empty one out we should
- # get a form error
- nameservers_page.form["form-0-server"] = ""
- with less_console_noise(): # swallow logged warning message
- result = nameservers_page.form.submit()
- # form submission was a post with an error, response should be a 200
- # error text appears four times, twice at the top of the page,
- # once around each required field.
- self.assertContains(
- result,
- "At least two name servers are required.",
- count=4,
- status_code=200,
- )
-
-
-class TestDomainAuthorizingOfficial(TestDomainOverview):
- def test_domain_authorizing_official(self):
- """Can load domain's authorizing official page."""
- page = self.client.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
- # once on the sidebar, once in the title
- self.assertContains(page, "Authorizing official", count=2)
-
- def test_domain_authorizing_official_content(self):
- """Authorizing official information appears on the page."""
- self.domain_information.authorizing_official = Contact(first_name="Testy")
- self.domain_information.authorizing_official.save()
- self.domain_information.save()
- page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Testy")
-
- def test_domain_edit_authorizing_official_in_place(self):
- """When editing an authorizing official for domain information and AO is not
- joined to any other objects"""
- self.domain_information.authorizing_official = Contact(
- first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov"
- )
- self.domain_information.authorizing_official.save()
- self.domain_information.save()
- ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_form = ao_page.forms[0]
- self.assertEqual(ao_form["first_name"].value, "Testy")
- ao_form["first_name"] = "Testy2"
- # ao_pk is the initial pk of the authorizing official. set it before update
- # to be able to verify after update that the same contact object is in place
- ao_pk = self.domain_information.authorizing_official.id
- ao_form.submit()
-
- # refresh domain information
- self.domain_information.refresh_from_db()
- self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name)
- self.assertEqual(ao_pk, self.domain_information.authorizing_official.id)
-
- def test_domain_edit_authorizing_official_creates_new(self):
- """When editing an authorizing official for domain information and AO IS
- joined to another object"""
- # set AO and Other Contact to the same Contact object
- self.domain_information.authorizing_official = Contact(
- first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov"
- )
- self.domain_information.authorizing_official.save()
- self.domain_information.save()
- self.domain_information.other_contacts.add(self.domain_information.authorizing_official)
- self.domain_information.save()
- # load the Authorizing Official in the web form
- ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- ao_form = ao_page.forms[0]
- # verify the first name is "Testy" and then change it to "Testy2"
- self.assertEqual(ao_form["first_name"].value, "Testy")
- ao_form["first_name"] = "Testy2"
- # ao_pk is the initial pk of the authorizing official. set it before update
- # to be able to verify after update that the same contact object is in place
- ao_pk = self.domain_information.authorizing_official.id
- ao_form.submit()
-
- # refresh domain information
- self.domain_information.refresh_from_db()
- # assert that AO information is updated, and that the AO is a new Contact
- self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name)
- self.assertNotEqual(ao_pk, self.domain_information.authorizing_official.id)
- # assert that the Other Contact information is not updated and that the Other Contact
- # is the original Contact object
- other_contact = self.domain_information.other_contacts.all()[0]
- self.assertEqual("Testy", other_contact.first_name)
- self.assertEqual(ao_pk, other_contact.id)
-
-
-class TestDomainOrganization(TestDomainOverview):
- def test_domain_org_name_address(self):
- """Can load domain's org name and mailing address page."""
- page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
- # once on the sidebar, once in the page title, once as H1
- self.assertContains(page, "Organization name and mailing address", count=3)
-
- def test_domain_org_name_address_content(self):
- """Org name and address information appears on the page."""
- self.domain_information.organization_name = "Town of Igorville"
- self.domain_information.save()
- page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Town of Igorville")
-
- def test_domain_org_name_address_form(self):
- """Submitting changes works on the org name address page."""
- self.domain_information.organization_name = "Town of Igorville"
- self.domain_information.save()
- org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
-
- org_name_page.form["organization_name"] = "Not igorville"
- org_name_page.form["city"] = "Faketown"
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- success_result_page = org_name_page.form.submit()
- self.assertEqual(success_result_page.status_code, 200)
-
- self.assertContains(success_result_page, "Not igorville")
- self.assertContains(success_result_page, "Faketown")
-
-
-class TestDomainContactInformation(TestDomainOverview):
- def test_domain_your_contact_information(self):
- """Can load domain's your contact information page."""
- page = self.client.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Your contact information")
-
- def test_domain_your_contact_information_content(self):
- """Logged-in user's contact information appears on the page."""
- self.user.contact.first_name = "Testy"
- self.user.contact.save()
- page = self.app.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Testy")
-
-
-class TestDomainSecurityEmail(TestDomainOverview):
- def test_domain_security_email_existing_security_contact(self):
- """Can load domain's security email page."""
- self.mockSendPatch = patch("registrar.models.domain.registry.send")
- self.mockedSendFunction = self.mockSendPatch.start()
- self.mockedSendFunction.side_effect = self.mockSend
-
- domain_contact, _ = Domain.objects.get_or_create(name="freeman.gov")
- # Add current user to this domain
- _ = UserDomainRole(user=self.user, domain=domain_contact, role="admin").save()
- page = self.client.get(reverse("domain-security-email", kwargs={"pk": domain_contact.id}))
-
- # Loads correctly
- self.assertContains(page, "Security email")
- self.assertContains(page, "security@mail.gov")
- self.mockSendPatch.stop()
-
- def test_domain_security_email_no_security_contact(self):
- """Loads a domain with no defined security email.
- We should not show the default."""
- self.mockSendPatch = patch("registrar.models.domain.registry.send")
- self.mockedSendFunction = self.mockSendPatch.start()
- self.mockedSendFunction.side_effect = self.mockSend
-
- page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
-
- # Loads correctly
- self.assertContains(page, "Security email")
- self.assertNotContains(page, "dotgov@cisa.dhs.gov")
- self.mockSendPatch.stop()
-
- def test_domain_security_email(self):
- """Can load domain's security email page."""
- page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Security email")
-
- def test_domain_security_email_form(self):
- """Adding a security email works.
- Uses self.app WebTest because we need to interact with forms.
- """
- security_email_page = self.app.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- security_email_page.form["security_email"] = "mayor@igorville.gov"
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- mock_client = MagicMock()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise(): # swallow log warning message
- result = security_email_page.form.submit()
- self.assertEqual(result.status_code, 302)
- self.assertEqual(
- result["Location"],
- reverse("domain-security-email", kwargs={"pk": self.domain.id}),
- )
-
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- success_page = result.follow()
- self.assertContains(success_page, "The security email for this domain has been updated")
-
- def test_security_email_form_messages(self):
- """
- Test against the success and error messages that are defined in the view
- """
- p = "adminpass"
- self.client.login(username="superuser", password=p)
-
- form_data_registry_error = {
- "security_email": "test@failCreate.gov",
- }
-
- form_data_contact_error = {
- "security_email": "test@contactError.gov",
- }
-
- form_data_success = {
- "security_email": "test@something.gov",
- }
-
- test_cases = [
- (
- "RegistryError",
- form_data_registry_error,
- str(GenericError(code=GenericErrorCodes.CANNOT_CONTACT_REGISTRY)),
- ),
- (
- "ContactError",
- form_data_contact_error,
- str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)),
- ),
- (
- "RegistrySuccess",
- form_data_success,
- "The security email for this domain has been updated.",
- ),
- # Add more test cases with different scenarios here
- ]
-
- for test_name, data, expected_message in test_cases:
- response = self.client.post(
- reverse("domain-security-email", kwargs={"pk": self.domain.id}),
- data=data,
- follow=True,
- )
-
- # Check the response status code, content, or any other relevant assertions
- self.assertEqual(response.status_code, 200)
-
- # Check if the expected message tag is set
- if test_name == "RegistryError" or test_name == "ContactError":
- message_tag = "error"
- elif test_name == "RegistrySuccess":
- message_tag = "success"
- else:
- # Handle other cases if needed
- message_tag = "info" # Change to the appropriate default
-
- # Check the message tag
- messages = list(response.context["messages"])
- self.assertEqual(len(messages), 1)
- message = messages[0]
- self.assertEqual(message.tags, message_tag)
- self.assertEqual(message.message.strip(), expected_message.strip())
-
- def test_domain_overview_blocked_for_ineligible_user(self):
- """We could easily duplicate this test for all domain management
- views, but a single url test should be solid enough since all domain
- management pages share the same permissions class"""
- self.user.status = User.RESTRICTED
- self.user.save()
- home_page = self.app.get("/")
- self.assertContains(home_page, "igorville.gov")
- with less_console_noise():
- response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
- self.assertEqual(response.status_code, 403)
-
-
-class TestDomainDNSSEC(TestDomainOverview):
-
- """MockEPPLib is already inherited."""
-
- def test_dnssec_page_refreshes_enable_button(self):
- """DNSSEC overview page loads when domain has no DNSSEC data
- and shows a 'Enable DNSSEC' button."""
-
- page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}))
- self.assertContains(page, "Enable DNSSEC")
-
- def test_dnssec_page_loads_with_data_in_domain(self):
- """DNSSEC overview page loads when domain has DNSSEC data
- and the template contains a button to disable DNSSEC."""
-
- page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id}))
- self.assertContains(page, "Disable DNSSEC")
-
- # Prepare the data for the POST request
- post_data = {
- "disable_dnssec": "Disable DNSSEC",
- }
- updated_page = self.client.post(
- reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}),
- post_data,
- follow=True,
- )
-
- self.assertEqual(updated_page.status_code, 200)
-
- self.assertContains(updated_page, "Enable DNSSEC")
-
- def test_ds_form_loads_with_no_domain_data(self):
- """DNSSEC Add DS data page loads when there is no
- domain DNSSEC data and shows a button to Add new record"""
-
- page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id}))
- self.assertContains(page, "You have no DS data added")
- self.assertContains(page, "Add new record")
-
- def test_ds_form_loads_with_ds_data(self):
- """DNSSEC Add DS data page loads when there is
- domain DNSSEC DS data and shows the data"""
-
- page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- self.assertContains(page, "DS data record 1")
-
- def test_ds_data_form_modal(self):
- """When user clicks on save, a modal pops up."""
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- # Assert that a hidden trigger for the modal does not exist.
- # This hidden trigger will pop on the page when certain condition are met:
- # 1) Initial form contained DS data, 2) All data is deleted and form is
- # submitted.
- self.assertNotContains(add_data_page, "Trigger Disable DNSSEC Modal")
- # Simulate a delete all data
- form_data = {}
- response = self.client.post(
- reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}),
- data=form_data,
- )
- self.assertEqual(response.status_code, 200) # Adjust status code as needed
- # Now check to see whether the JS trigger for the modal is present on the page
- self.assertContains(response, "Trigger Disable DNSSEC Modal")
-
- def test_ds_data_form_submits(self):
- """DS data form submits successfully
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- with less_console_noise(): # swallow log warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post, response should be a redirect
- self.assertEqual(result.status_code, 302)
- self.assertEqual(
- result["Location"],
- reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}),
- )
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- page = result.follow()
- self.assertContains(page, "The DS data records for this domain have been updated.")
-
- def test_ds_data_form_invalid(self):
- """DS data form errors with invalid data (missing required fields)
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # all four form fields are required, so will test with each blank
- add_data_page.forms[0]["form-0-key_tag"] = ""
- add_data_page.forms[0]["form-0-algorithm"] = ""
- add_data_page.forms[0]["form-0-digest_type"] = ""
- add_data_page.forms[0]["form-0-digest"] = ""
- with less_console_noise(): # swallow logged warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the field.
- self.assertContains(result, "Key tag is required", count=2, status_code=200)
- self.assertContains(result, "Algorithm is required", count=2, status_code=200)
- self.assertContains(result, "Digest type is required", count=2, status_code=200)
- self.assertContains(result, "Digest is required", count=2, status_code=200)
-
- def test_ds_data_form_invalid_keytag(self):
- """DS data form errors with invalid data (key tag too large)
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # first two nameservers are required, so if we empty one out we should
- # get a form error
- add_data_page.forms[0]["form-0-key_tag"] = "65536" # > 65535
- add_data_page.forms[0]["form-0-algorithm"] = ""
- add_data_page.forms[0]["form-0-digest_type"] = ""
- add_data_page.forms[0]["form-0-digest"] = ""
- with less_console_noise(): # swallow logged warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the field.
- self.assertContains(
- result, str(DsDataError(code=DsDataErrorCodes.INVALID_KEYTAG_SIZE)), count=2, status_code=200
- )
-
- def test_ds_data_form_invalid_digest_chars(self):
- """DS data form errors with invalid data (digest contains non hexadecimal chars)
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # first two nameservers are required, so if we empty one out we should
- # get a form error
- add_data_page.forms[0]["form-0-key_tag"] = "1234"
- add_data_page.forms[0]["form-0-algorithm"] = "3"
- add_data_page.forms[0]["form-0-digest_type"] = "1"
- add_data_page.forms[0]["form-0-digest"] = "GG1234"
- with less_console_noise(): # swallow logged warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the field.
- self.assertContains(
- result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_CHARS)), count=2, status_code=200
- )
-
- def test_ds_data_form_invalid_digest_sha1(self):
- """DS data form errors with invalid data (digest is invalid sha-1)
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # first two nameservers are required, so if we empty one out we should
- # get a form error
- add_data_page.forms[0]["form-0-key_tag"] = "1234"
- add_data_page.forms[0]["form-0-algorithm"] = "3"
- add_data_page.forms[0]["form-0-digest_type"] = "1" # SHA-1
- add_data_page.forms[0]["form-0-digest"] = "A123"
- with less_console_noise(): # swallow logged warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the field.
- self.assertContains(
- result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA1)), count=2, status_code=200
- )
-
- def test_ds_data_form_invalid_digest_sha256(self):
- """DS data form errors with invalid data (digest is invalid sha-256)
-
- Uses self.app WebTest because we need to interact with forms.
- """
- add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
- session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
- self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # first two nameservers are required, so if we empty one out we should
- # get a form error
- add_data_page.forms[0]["form-0-key_tag"] = "1234"
- add_data_page.forms[0]["form-0-algorithm"] = "3"
- add_data_page.forms[0]["form-0-digest_type"] = "2" # SHA-256
- add_data_page.forms[0]["form-0-digest"] = "GG1234"
- with less_console_noise(): # swallow logged warning message
- result = add_data_page.forms[0].submit()
- # form submission was a post with an error, response should be a 200
- # error text appears twice, once at the top of the page, once around
- # the field.
- self.assertContains(
- result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA256)), count=2, status_code=200
- )
-
-
-class TestApplicationStatus(TestWithUser, WebTest):
- def setUp(self):
- super().setUp()
- self.app.set_user(self.user.username)
- self.client.force_login(self.user)
-
- def test_application_status(self):
- """Checking application status page"""
- application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
- application.save()
-
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- # click the "Manage" link
- detail_page = home_page.click("Manage", index=0)
- self.assertContains(detail_page, "city.gov")
- self.assertContains(detail_page, "city1.gov")
- self.assertContains(detail_page, "Chief Tester")
- self.assertContains(detail_page, "testy@town.com")
- self.assertContains(detail_page, "Admin Tester")
- self.assertContains(detail_page, "Status:")
-
- def test_application_status_with_ineligible_user(self):
- """Checking application status page whith a blocked user.
- The user should still have access to view."""
- self.user.status = "ineligible"
- self.user.save()
-
- application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
- application.save()
-
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- # click the "Manage" link
- detail_page = home_page.click("Manage", index=0)
- self.assertContains(detail_page, "city.gov")
- self.assertContains(detail_page, "Chief Tester")
- self.assertContains(detail_page, "testy@town.com")
- self.assertContains(detail_page, "Admin Tester")
- self.assertContains(detail_page, "Status:")
-
- def test_application_withdraw(self):
- """Checking application status page"""
- application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
- application.save()
-
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- # click the "Manage" link
- detail_page = home_page.click("Manage", index=0)
- self.assertContains(detail_page, "city.gov")
- self.assertContains(detail_page, "city1.gov")
- self.assertContains(detail_page, "Chief Tester")
- self.assertContains(detail_page, "testy@town.com")
- self.assertContains(detail_page, "Admin Tester")
- self.assertContains(detail_page, "Status:")
- # click the "Withdraw request" button
- mock_client = MockSESClient()
- with boto3_mocking.clients.handler_for("sesv2", mock_client):
- with less_console_noise():
- withdraw_page = detail_page.click("Withdraw request")
- self.assertContains(withdraw_page, "Withdraw request for")
- home_page = withdraw_page.click("Withdraw request")
- # confirm that it has redirected, and the status has been updated to withdrawn
- self.assertRedirects(
- home_page,
- "/",
- status_code=302,
- target_status_code=200,
- fetch_redirect_response=True,
- )
- home_page = self.app.get("/")
- self.assertContains(home_page, "Withdrawn")
-
- def test_application_withdraw_no_permissions(self):
- """Can't withdraw applications as a restricted user."""
- self.user.status = User.RESTRICTED
- self.user.save()
- application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
- application.save()
-
- home_page = self.app.get("/")
- self.assertContains(home_page, "city.gov")
- # click the "Manage" link
- detail_page = home_page.click("Manage", index=0)
- self.assertContains(detail_page, "city.gov")
- self.assertContains(detail_page, "city1.gov")
- self.assertContains(detail_page, "Chief Tester")
- self.assertContains(detail_page, "testy@town.com")
- self.assertContains(detail_page, "Admin Tester")
- self.assertContains(detail_page, "Status:")
- # Restricted user trying to withdraw results in 403 error
- with less_console_noise():
- for url_name in [
- "application-withdraw-confirmation",
- "application-withdrawn",
- ]:
- with self.subTest(url_name=url_name):
- page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
- self.assertEqual(page.status_code, 403)
-
- def test_application_status_no_permissions(self):
- """Can't access applications without being the creator."""
- application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
- other_user = User()
- other_user.save()
- application.creator = other_user
- application.save()
-
- # PermissionDeniedErrors make lots of noise in test output
- with less_console_noise():
- for url_name in [
- "application-status",
- "application-withdraw-confirmation",
- "application-withdrawn",
- ]:
- with self.subTest(url_name=url_name):
- page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
- self.assertEqual(page.status_code, 403)
-
- def test_approved_application_not_in_active_requests(self):
- """An approved application is not shown in the Active
- Requests table on home.html."""
- application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED, user=self.user)
- application.save()
-
- home_page = self.app.get("/")
- # This works in our test environment because creating
- # an approved application here does not generate a
- # domain object, so we do not expect to see 'city.gov'
- # in either the Domains or Requests tables.
- self.assertNotContains(home_page, "city.gov")
diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py
new file mode 100644
index 000000000..62485fa86
--- /dev/null
+++ b/src/registrar/tests/test_views_application.py
@@ -0,0 +1,2199 @@
+from unittest import skip
+
+from django.conf import settings
+from django.urls import reverse
+
+from .common import MockSESClient, completed_application # type: ignore
+from django_webtest import WebTest # type: ignore
+import boto3_mocking # type: ignore
+
+from registrar.models import (
+ DomainApplication,
+ Domain,
+ DomainInformation,
+ Contact,
+ User,
+ Website,
+)
+from registrar.views.application import ApplicationWizard, Step
+
+from .common import less_console_noise
+from .test_views import TestWithUser
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class DomainApplicationTests(TestWithUser, WebTest):
+
+ """Webtests for domain application to test filling and submitting."""
+
+ # Doesn't work with CSRF checking
+ # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest
+ csrf_checks = False
+
+ def setUp(self):
+ super().setUp()
+ self.app.set_user(self.user.username)
+ self.TITLES = ApplicationWizard.TITLES
+
+ def test_application_form_intro_acknowledgement(self):
+ """Tests that user is presented with intro acknowledgement page"""
+ intro_page = self.app.get(reverse("application:"))
+ self.assertContains(intro_page, "You’re about to start your .gov domain request")
+
+ def test_application_form_intro_is_skipped_when_edit_access(self):
+ """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'"""
+ completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user)
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ # click the "Edit" link
+ detail_page = home_page.click("Edit", index=0)
+ # Check that the response is a redirect
+ self.assertEqual(detail_page.status_code, 302)
+ # You can access the 'Location' header to get the redirect URL
+ redirect_url = detail_page.url
+ self.assertEqual(redirect_url, "/request/organization_type/")
+
+ def test_application_form_empty_submit(self):
+ """Tests empty submit on the first page after the acknowledgement page"""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # submitting should get back the same page if the required field is empty
+ result = type_page.forms[0].submit()
+ self.assertIn("What kind of U.S.-based government organization do you represent?", result)
+
+ def test_application_multiple_applications_exist(self):
+ """Test that an info message appears when user has multiple applications already"""
+ # create and submit an application
+ application = completed_application(user=self.user)
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ application.submit()
+ application.save()
+
+ # now, attempt to create another one
+ with less_console_noise():
+ intro_page = self.app.get(reverse("application:"))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ self.assertContains(type_page, "You cannot submit this request yet")
+
+ @boto3_mocking.patching
+ def test_application_form_submission(self):
+ """
+ Can fill out the entire form and submit.
+ As we add additional form pages, we need to include them here to make
+ this test work.
+
+ This test also looks for the long organization name on the summary page.
+
+ This also tests for the presence of a modal trigger and the dynamic test
+ in the modal header on the submit page.
+ """
+ num_pages_tested = 0
+ # elections, type_of_work, tribal_government
+ SKIPPED_PAGES = 3
+ num_pages = len(self.TITLES) - SKIPPED_PAGES
+
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # ---- TYPE PAGE ----
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "federal"
+ # test next button and validate data
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+ # should see results in db
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.organization_type, "federal")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(type_result.status_code, 302)
+ self.assertEqual(type_result["Location"], "/request/organization_federal/")
+ num_pages_tested += 1
+
+ # ---- FEDERAL BRANCH PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ federal_page = type_result.follow()
+ federal_form = federal_page.forms[0]
+ federal_form["organization_federal-federal_type"] = "executive"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_result = federal_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.federal_type, "executive")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(federal_result.status_code, 302)
+ self.assertEqual(federal_result["Location"], "/request/organization_contact/")
+ num_pages_tested += 1
+
+ # ---- ORG CONTACT PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_page = federal_result.follow()
+ org_contact_form = org_contact_page.forms[0]
+ # federal agency so we have to fill in federal_agency
+ org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
+ org_contact_form["organization_contact-organization_name"] = "Testorg"
+ org_contact_form["organization_contact-address_line1"] = "address 1"
+ org_contact_form["organization_contact-address_line2"] = "address 2"
+ org_contact_form["organization_contact-city"] = "NYC"
+ org_contact_form["organization_contact-state_territory"] = "NY"
+ org_contact_form["organization_contact-zipcode"] = "10002"
+ org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_result = org_contact_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.organization_name, "Testorg")
+ self.assertEqual(application.address_line1, "address 1")
+ self.assertEqual(application.address_line2, "address 2")
+ self.assertEqual(application.city, "NYC")
+ self.assertEqual(application.state_territory, "NY")
+ self.assertEqual(application.zipcode, "10002")
+ self.assertEqual(application.urbanization, "URB Royal Oaks")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(org_contact_result.status_code, 302)
+ self.assertEqual(org_contact_result["Location"], "/request/authorizing_official/")
+ num_pages_tested += 1
+
+ # ---- AUTHORIZING OFFICIAL PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page = org_contact_result.follow()
+ ao_form = ao_page.forms[0]
+ ao_form["authorizing_official-first_name"] = "Testy ATO"
+ ao_form["authorizing_official-last_name"] = "Tester ATO"
+ ao_form["authorizing_official-title"] = "Chief Tester"
+ ao_form["authorizing_official-email"] = "testy@town.com"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_result = ao_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.authorizing_official.first_name, "Testy ATO")
+ self.assertEqual(application.authorizing_official.last_name, "Tester ATO")
+ self.assertEqual(application.authorizing_official.title, "Chief Tester")
+ self.assertEqual(application.authorizing_official.email, "testy@town.com")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(ao_result.status_code, 302)
+ self.assertEqual(ao_result["Location"], "/request/current_sites/")
+ num_pages_tested += 1
+
+ # ---- CURRENT SITES PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_page = ao_result.follow()
+ current_sites_form = current_sites_page.forms[0]
+ current_sites_form["current_sites-0-website"] = "www.city.com"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_result = current_sites_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(
+ application.current_websites.filter(website="http://www.city.com").count(),
+ 1,
+ )
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(current_sites_result.status_code, 302)
+ self.assertEqual(current_sites_result["Location"], "/request/dotgov_domain/")
+ num_pages_tested += 1
+
+ # ---- DOTGOV DOMAIN PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ dotgov_page = current_sites_result.follow()
+ dotgov_form = dotgov_page.forms[0]
+ dotgov_form["dotgov_domain-requested_domain"] = "city"
+ dotgov_form["dotgov_domain-0-alternative_domain"] = "city1"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ dotgov_result = dotgov_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.requested_domain.name, "city.gov")
+ self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1)
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(dotgov_result.status_code, 302)
+ self.assertEqual(dotgov_result["Location"], "/request/purpose/")
+ num_pages_tested += 1
+
+ # ---- PURPOSE PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ purpose_page = dotgov_result.follow()
+ purpose_form = purpose_page.forms[0]
+ purpose_form["purpose-purpose"] = "For all kinds of things."
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ purpose_result = purpose_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.purpose, "For all kinds of things.")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(purpose_result.status_code, 302)
+ self.assertEqual(purpose_result["Location"], "/request/your_contact/")
+ num_pages_tested += 1
+
+ # ---- YOUR CONTACT INFO PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ your_contact_page = purpose_result.follow()
+ your_contact_form = your_contact_page.forms[0]
+
+ your_contact_form["your_contact-first_name"] = "Testy you"
+ your_contact_form["your_contact-last_name"] = "Tester you"
+ your_contact_form["your_contact-title"] = "Admin Tester"
+ your_contact_form["your_contact-email"] = "testy-admin@town.com"
+ your_contact_form["your_contact-phone"] = "(201) 555 5556"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ your_contact_result = your_contact_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.submitter.first_name, "Testy you")
+ self.assertEqual(application.submitter.last_name, "Tester you")
+ self.assertEqual(application.submitter.title, "Admin Tester")
+ self.assertEqual(application.submitter.email, "testy-admin@town.com")
+ self.assertEqual(application.submitter.phone, "(201) 555 5556")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(your_contact_result.status_code, 302)
+ self.assertEqual(your_contact_result["Location"], "/request/other_contacts/")
+ num_pages_tested += 1
+
+ # ---- OTHER CONTACTS PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ other_contacts_page = your_contact_result.follow()
+
+ # This page has 3 forms in 1.
+ # Let's set the yes/no radios to enable the other contacts fieldsets
+ other_contacts_form = other_contacts_page.forms[0]
+
+ other_contacts_form["other_contacts-has_other_contacts"] = "True"
+
+ other_contacts_form["other_contacts-0-first_name"] = "Testy2"
+ other_contacts_form["other_contacts-0-last_name"] = "Tester2"
+ other_contacts_form["other_contacts-0-title"] = "Another Tester"
+ other_contacts_form["other_contacts-0-email"] = "testy2@town.com"
+ other_contacts_form["other_contacts-0-phone"] = "(201) 555 5557"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ other_contacts_result = other_contacts_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(
+ application.other_contacts.filter(
+ first_name="Testy2",
+ last_name="Tester2",
+ title="Another Tester",
+ email="testy2@town.com",
+ phone="(201) 555 5557",
+ ).count(),
+ 1,
+ )
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(other_contacts_result.status_code, 302)
+ self.assertEqual(other_contacts_result["Location"], "/request/anything_else/")
+ num_pages_tested += 1
+
+ # ---- ANYTHING ELSE PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ anything_else_page = other_contacts_result.follow()
+ anything_else_form = anything_else_page.forms[0]
+
+ anything_else_form["anything_else-anything_else"] = "Nothing else."
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ anything_else_result = anything_else_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.anything_else, "Nothing else.")
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(anything_else_result.status_code, 302)
+ self.assertEqual(anything_else_result["Location"], "/request/requirements/")
+ num_pages_tested += 1
+
+ # ---- REQUIREMENTS PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ requirements_page = anything_else_result.follow()
+ requirements_form = requirements_page.forms[0]
+
+ requirements_form["requirements-is_policy_acknowledged"] = True
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ requirements_result = requirements_form.submit()
+ # validate that data from this step are being saved
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(application.is_policy_acknowledged, True)
+ # the post request should return a redirect to the next form in
+ # the application
+ self.assertEqual(requirements_result.status_code, 302)
+ self.assertEqual(requirements_result["Location"], "/request/review/")
+ num_pages_tested += 1
+
+ # ---- REVIEW AND FINSIHED PAGES ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ review_page = requirements_result.follow()
+ review_form = review_page.forms[0]
+
+ # Review page contains all the previously entered data
+ # Let's make sure the long org name is displayed
+ self.assertContains(review_page, "Federal")
+ self.assertContains(review_page, "Executive")
+ self.assertContains(review_page, "Testorg")
+ self.assertContains(review_page, "address 1")
+ self.assertContains(review_page, "address 2")
+ self.assertContains(review_page, "NYC")
+ self.assertContains(review_page, "NY")
+ self.assertContains(review_page, "10002")
+ self.assertContains(review_page, "URB Royal Oaks")
+ self.assertContains(review_page, "Testy ATO")
+ self.assertContains(review_page, "Tester ATO")
+ self.assertContains(review_page, "Chief Tester")
+ self.assertContains(review_page, "testy@town.com")
+ self.assertContains(review_page, "city.com")
+ self.assertContains(review_page, "city.gov")
+ self.assertContains(review_page, "city1.gov")
+ self.assertContains(review_page, "For all kinds of things.")
+ self.assertContains(review_page, "Testy you")
+ self.assertContains(review_page, "Tester you")
+ self.assertContains(review_page, "Admin Tester")
+ self.assertContains(review_page, "testy-admin@town.com")
+ self.assertContains(review_page, "(201) 555-5556")
+ self.assertContains(review_page, "Testy2")
+ self.assertContains(review_page, "Tester2")
+ self.assertContains(review_page, "Another Tester")
+ self.assertContains(review_page, "testy2@town.com")
+ self.assertContains(review_page, "(201) 555-5557")
+ self.assertContains(review_page, "Nothing else.")
+
+ # We can't test the modal itself as it relies on JS for init and triggering,
+ # but we can test for the existence of its trigger:
+ self.assertContains(review_page, "toggle-submit-domain-request")
+ # And the existence of the modal's data parked and ready for the js init.
+ # The next assert also tests for the passed requested domain context from
+ # the view > application_form > modal
+ self.assertContains(review_page, "You are about to submit a domain request for city.gov")
+
+ # final submission results in a redirect to the "finished" URL
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ with less_console_noise():
+ review_result = review_form.submit()
+
+ self.assertEqual(review_result.status_code, 302)
+ self.assertEqual(review_result["Location"], "/request/finished/")
+ num_pages_tested += 1
+
+ # following this redirect is a GET request, so include the cookie
+ # here too.
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ with less_console_noise():
+ final_result = review_result.follow()
+ self.assertContains(final_result, "Thanks for your domain request!")
+
+ # check that any new pages are added to this test
+ self.assertEqual(num_pages, num_pages_tested)
+
+ # This is the start of a test to check an existing application, it currently
+ # does not work and results in errors as noted in:
+ # https://github.com/cisagov/getgov/pull/728
+ @skip("WIP")
+ def test_application_form_started_allsteps(self):
+ num_pages_tested = 0
+ # elections, type_of_work, tribal_government
+ SKIPPED_PAGES = 3
+ DASHBOARD_PAGE = 1
+ num_pages = len(self.TITLES) - SKIPPED_PAGES + DASHBOARD_PAGE
+
+ application = completed_application(user=self.user)
+ application.save()
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ self.assertContains(home_page, "Started")
+ num_pages_tested += 1
+
+ # TODO: For some reason this click results in a new application being generated
+ # This appraoch is an alternatie to using get as is being done below
+ #
+ # type_page = home_page.click("Edit")
+
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ url = reverse("edit-application", kwargs={"id": application.pk})
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # TODO: The following line results in a django error on middleware
+ response = self.client.get(url, follow=True)
+ self.assertContains(response, "Type of organization")
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # TODO: Step through the remaining pages
+
+ self.assertEqual(num_pages, num_pages_tested)
+
+ def test_application_form_conditional_federal(self):
+ """Federal branch question is shown for federal organizations."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # ---- TYPE PAGE ----
+
+ # the conditional step titles shouldn't appear initially
+ self.assertNotContains(type_page, self.TITLES["organization_federal"])
+ self.assertNotContains(type_page, self.TITLES["organization_election"])
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "federal"
+
+ # set the session ID before .submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # the post request should return a redirect to the federal branch
+ # question
+ self.assertEqual(type_result.status_code, 302)
+ self.assertEqual(type_result["Location"], "/request/organization_federal/")
+
+ # and the step label should appear in the sidebar of the resulting page
+ # but the step label for the elections page should not appear
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_page = type_result.follow()
+ self.assertContains(federal_page, self.TITLES["organization_federal"])
+ self.assertNotContains(federal_page, self.TITLES["organization_election"])
+
+ # continuing on in the flow we need to see top-level agency on the
+ # contact page
+ federal_page.forms[0]["organization_federal-federal_type"] = "executive"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_result = federal_page.forms[0].submit()
+ # the post request should return a redirect to the contact
+ # question
+ self.assertEqual(federal_result.status_code, 302)
+ self.assertEqual(federal_result["Location"], "/request/organization_contact/")
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_page = federal_result.follow()
+ self.assertContains(contact_page, "Federal agency")
+
+ def test_application_form_conditional_elections(self):
+ """Election question is shown for other organizations."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # ---- TYPE PAGE ----
+
+ # the conditional step titles shouldn't appear initially
+ self.assertNotContains(type_page, self.TITLES["organization_federal"])
+ self.assertNotContains(type_page, self.TITLES["organization_election"])
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "county"
+
+ # set the session ID before .submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # the post request should return a redirect to the elections question
+ self.assertEqual(type_result.status_code, 302)
+ self.assertEqual(type_result["Location"], "/request/organization_election/")
+
+ # and the step label should appear in the sidebar of the resulting page
+ # but the step label for the elections page should not appear
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ election_page = type_result.follow()
+ self.assertContains(election_page, self.TITLES["organization_election"])
+ self.assertNotContains(election_page, self.TITLES["organization_federal"])
+
+ # continuing on in the flow we need to NOT see top-level agency on the
+ # contact page
+ election_page.forms[0]["organization_election-is_election_board"] = "True"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ election_result = election_page.forms[0].submit()
+ # the post request should return a redirect to the contact
+ # question
+ self.assertEqual(election_result.status_code, 302)
+ self.assertEqual(election_result["Location"], "/request/organization_contact/")
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_page = election_result.follow()
+ self.assertNotContains(contact_page, "Federal agency")
+
+ def test_application_form_section_skipping(self):
+ """Can skip forward and back in sections"""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "federal"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_page = type_result.follow()
+
+ # Now on federal type page, click back to the organization type
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ new_page = federal_page.click(str(self.TITLES["organization_type"]), index=0)
+
+ # Should be a link to the organization_federal page
+ self.assertGreater(
+ len(new_page.html.find_all("a", href="/request/organization_federal/")),
+ 0,
+ )
+
+ def test_application_form_nonfederal(self):
+ """Non-federal organizations don't have to provide their federal agency."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_page = type_result.follow()
+ org_contact_form = contact_page.forms[0]
+
+ self.assertNotIn("federal_agency", org_contact_form.fields)
+
+ # minimal fields that must be filled out
+ org_contact_form["organization_contact-organization_name"] = "Testorg"
+ org_contact_form["organization_contact-address_line1"] = "address 1"
+ org_contact_form["organization_contact-city"] = "NYC"
+ org_contact_form["organization_contact-state_territory"] = "NY"
+ org_contact_form["organization_contact-zipcode"] = "10002"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_result = org_contact_form.submit()
+
+ # the post request should return a redirect to the
+ # about your organization page if it was successful.
+ self.assertEqual(contact_result.status_code, 302)
+ self.assertEqual(contact_result["Location"], "/request/about_your_organization/")
+
+ def test_application_about_your_organization_special(self):
+ """Special districts have to answer an additional question."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_page.forms[0].submit()
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_page = type_result.follow()
+
+ self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION])
+
+ def test_yes_no_form_inits_blank_for_new_application(self):
+ """On the Other Contacts page, the yes/no form gets initialized with nothing selected for
+ new applications"""
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None)
+
+ def test_yes_no_form_inits_yes_for_application_with_other_contacts(self):
+ """On the Other Contacts page, the yes/no form gets initialized with YES selected if the
+ application has other contacts"""
+ # Application has other contacts by default
+ application = completed_application(user=self.user)
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
+
+ def test_yes_no_form_inits_no_for_application_with_no_other_contacts_rationale(self):
+ """On the Other Contacts page, the yes/no form gets initialized with NO selected if the
+ application has no other contacts"""
+ # Application has other contacts by default
+ application = completed_application(user=self.user, has_other_contacts=False)
+ application.no_other_contacts_rationale = "Hello!"
+ application.save()
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False")
+
+ def test_submitting_other_contacts_deletes_no_other_contacts_rationale(self):
+ """When a user submits the Other Contacts form with other contacts selected, the application's
+ no other contacts rationale gets deleted"""
+ # Application has other contacts by default
+ application = completed_application(user=self.user, has_other_contacts=False)
+ application.no_other_contacts_rationale = "Hello!"
+ application.save()
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False")
+
+ other_contacts_form["other_contacts-has_other_contacts"] = "True"
+
+ other_contacts_form["other_contacts-0-first_name"] = "Testy"
+ other_contacts_form["other_contacts-0-middle_name"] = ""
+ other_contacts_form["other_contacts-0-last_name"] = "McTesterson"
+ other_contacts_form["other_contacts-0-title"] = "Lord"
+ other_contacts_form["other_contacts-0-email"] = "testy@abc.org"
+ other_contacts_form["other_contacts-0-phone"] = "(201) 555-0123"
+
+ # Submit the now empty form
+ other_contacts_form.submit()
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database
+ application = DomainApplication.objects.get()
+ self.assertEqual(
+ application.other_contacts.count(),
+ 1,
+ )
+
+ self.assertEquals(
+ application.no_other_contacts_rationale,
+ None,
+ )
+
+ def test_submitting_no_other_contacts_rationale_deletes_other_contacts(self):
+ """When a user submits the Other Contacts form with no other contacts selected, the application's
+ other contacts get deleted for other contacts that exist and are not joined to other objects
+ """
+ # Application has other contacts by default
+ application = completed_application(user=self.user)
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
+
+ other_contacts_form["other_contacts-has_other_contacts"] = "False"
+
+ other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!"
+
+ # Submit the now empty form
+ other_contacts_form.submit()
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database
+ application = DomainApplication.objects.get()
+ self.assertEqual(
+ application.other_contacts.count(),
+ 0,
+ )
+
+ self.assertEquals(
+ application.no_other_contacts_rationale,
+ "Hello again!",
+ )
+
+ def test_submitting_no_other_contacts_rationale_removes_reference_other_contacts_when_joined(self):
+ """When a user submits the Other Contacts form with no other contacts selected, the application's
+ other contacts references get removed for other contacts that exist and are joined to other objects"""
+ # Populate the database with a domain application that
+ # has 1 "other contact" assigned to it
+ # We'll do it from scratch so we can reuse the other contact
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(555) 555 5555",
+ )
+ 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",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(other)
+
+ # Now let's join the other contact to another object
+ domain_info = DomainInformation.objects.create(creator=self.user)
+ domain_info.other_contacts.set([other])
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+ self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True")
+
+ other_contacts_form["other_contacts-has_other_contacts"] = "False"
+
+ other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!"
+
+ # Submit the now empty form
+ other_contacts_form.submit()
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application
+ application = DomainApplication.objects.get()
+ self.assertEqual(
+ application.other_contacts.count(),
+ 0,
+ )
+
+ # Verify that the 'other' contact object still exists
+ domain_info = DomainInformation.objects.get()
+ self.assertEqual(
+ domain_info.other_contacts.count(),
+ 1,
+ )
+ self.assertEqual(
+ domain_info.other_contacts.all()[0].first_name,
+ "Testy2",
+ )
+
+ self.assertEquals(
+ application.no_other_contacts_rationale,
+ "Hello again!",
+ )
+
+ def test_if_yes_no_form_is_no_then_no_other_contacts_required(self):
+ """Applicants with no other contacts have to give a reason."""
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ other_contacts_form = other_contacts_page.forms[0]
+ other_contacts_form["other_contacts-has_other_contacts"] = "False"
+ response = other_contacts_page.forms[0].submit()
+
+ # The textarea for no other contacts returns this error message
+ # Assert that it is returned, ie the no other contacts form is required
+ self.assertContains(response, "Rationale for no other employees is required.")
+
+ # The first name field for other contacts returns this error message
+ # Assert that it is not returned, ie the contacts form is not required
+ self.assertNotContains(response, "Enter the first name / given name of this contact.")
+
+ def test_if_yes_no_form_is_yes_then_other_contacts_required(self):
+ """Applicants with other contacts do not have to give a reason."""
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ other_contacts_form = other_contacts_page.forms[0]
+ other_contacts_form["other_contacts-has_other_contacts"] = "True"
+ response = other_contacts_page.forms[0].submit()
+
+ # The textarea for no other contacts returns this error message
+ # Assert that it is not returned, ie the no other contacts form is not required
+ self.assertNotContains(response, "Rationale for no other employees is required.")
+
+ # The first name field for other contacts returns this error message
+ # Assert that it is returned, ie the contacts form is required
+ self.assertContains(response, "Enter the first name / given name of this contact.")
+
+ def test_delete_other_contact(self):
+ """Other contacts can be deleted after being saved to database.
+
+ This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application,
+ loading the form and marking one contact up for deletion."""
+ # Populate the database with a domain application that
+ # has 2 "other contact" assigned to it
+ # We'll do it from scratch so we can reuse the other contact
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy you",
+ last_name="Tester you",
+ title="Admin Tester",
+ email="testy-admin@town.com",
+ phone="(201) 555 5556",
+ )
+ other, _ = Contact.objects.get_or_create(
+ first_name="Testy2",
+ last_name="Tester2",
+ title="Another Tester",
+ email="testy2@town.com",
+ phone="(201) 555 5557",
+ )
+ other2, _ = Contact.objects.get_or_create(
+ first_name="Testy3",
+ last_name="Tester3",
+ title="Another Tester",
+ email="testy3@town.com",
+ phone="(201) 555 5557",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(other)
+ application.other_contacts.add(other2)
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+
+ # Minimal check to ensure the form is loaded with both other contacts
+ self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
+ self.assertEqual(other_contacts_form["other_contacts-1-first_name"].value, "Testy3")
+
+ # Mark the first dude for deletion
+ other_contacts_form.set("other_contacts-0-DELETE", "on")
+
+ # Submit the form
+ other_contacts_form.submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # Verify that the first dude was deleted
+ application = DomainApplication.objects.get()
+ self.assertEqual(application.other_contacts.count(), 1)
+ self.assertEqual(application.other_contacts.first().first_name, "Testy3")
+
+ def test_delete_other_contact_does_not_allow_zero_contacts(self):
+ """Delete Other Contact does not allow submission with zero contacts."""
+ # Populate the database with a domain application that
+ # has 1 "other contact" assigned to it
+ # We'll do it from scratch so we can reuse the other contact
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy you",
+ last_name="Tester you",
+ title="Admin Tester",
+ email="testy-admin@town.com",
+ phone="(201) 555 5556",
+ )
+ other, _ = Contact.objects.get_or_create(
+ first_name="Testy2",
+ last_name="Tester2",
+ title="Another Tester",
+ email="testy2@town.com",
+ phone="(201) 555 5557",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(other)
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
+
+ # Mark the first dude for deletion
+ other_contacts_form.set("other_contacts-0-DELETE", "on")
+
+ # Submit the form
+ other_contacts_form.submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ # Verify that the contact was not deleted
+ application = DomainApplication.objects.get()
+ self.assertEqual(application.other_contacts.count(), 1)
+ self.assertEqual(application.other_contacts.first().first_name, "Testy2")
+
+ def test_delete_other_contact_sets_visible_empty_form_as_required_after_failed_submit(self):
+ """When you:
+ 1. add an empty contact,
+ 2. delete existing contacts,
+ 3. then submit,
+ The forms on page reload shows all the required fields and their errors."""
+
+ # Populate the database with a domain application that
+ # has 1 "other contact" assigned to it
+ # We'll do it from scratch so we can reuse the other contact
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy you",
+ last_name="Tester you",
+ title="Admin Tester",
+ email="testy-admin@town.com",
+ phone="(201) 555 5556",
+ )
+ other, _ = Contact.objects.get_or_create(
+ first_name="Testy2",
+ last_name="Tester2",
+ title="Another Tester",
+ email="testy2@town.com",
+ phone="(201) 555 5557",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(other)
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
+
+ # Set total forms to 2 indicating an additional formset was added.
+ # Submit no data though for the second formset.
+ # Set the first formset to be deleted.
+ other_contacts_form["other_contacts-TOTAL_FORMS"] = "2"
+ other_contacts_form.set("other_contacts-0-DELETE", "on")
+
+ response = other_contacts_form.submit()
+
+ # Assert that the response presents errors to the user, including to
+ # Enter the first name ...
+ self.assertContains(response, "Enter the first name / given name of this contact.")
+
+ def test_edit_other_contact_in_place(self):
+ """When you:
+ 1. edit an existing contact which is not joined to another model,
+ 2. then submit,
+ The application is linked to the existing contact, and the existing contact updated."""
+
+ # Populate the database with a domain application that
+ # has 1 "other contact" assigned to it
+ # We'll do it from scratch
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy you",
+ last_name="Tester you",
+ title="Admin Tester",
+ email="testy-admin@town.com",
+ phone="(201) 555 5556",
+ )
+ other, _ = Contact.objects.get_or_create(
+ first_name="Testy2",
+ last_name="Tester2",
+ title="Another Tester",
+ email="testy2@town.com",
+ phone="(201) 555 5557",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(other)
+
+ # other_contact_pk is the initial pk of the other contact. set it before update
+ # to be able to verify after update that the same contact object is in place
+ other_contact_pk = other.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2")
+
+ # update the first name of the contact
+ other_contacts_form["other_contacts-0-first_name"] = "Testy3"
+
+ # Submit the updated form
+ other_contacts_form.submit()
+
+ application.refresh_from_db()
+
+ # assert that the Other Contact is updated "in place"
+ other_contact = application.other_contacts.all()[0]
+ self.assertEquals(other_contact_pk, other_contact.id)
+ self.assertEquals("Testy3", other_contact.first_name)
+
+ def test_edit_other_contact_creates_new(self):
+ """When you:
+ 1. edit an existing contact which IS joined to another model,
+ 2. then submit,
+ The application is linked to a new contact, and the new contact is updated."""
+
+ # Populate the database with a domain application that
+ # has 1 "other contact" assigned to it, the other contact is also
+ # the authorizing official initially
+ # We'll do it from scratch
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy you",
+ last_name="Tester you",
+ title="Admin Tester",
+ email="testy-admin@town.com",
+ phone="(201) 555 5556",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(ao)
+
+ # other_contact_pk is the initial pk of the other contact. set it before update
+ # to be able to verify after update that the ao contact is still in place
+ # and not updated, and that the new contact has a new id
+ other_contact_pk = ao.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_page = self.app.get(reverse("application:other_contacts"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ other_contacts_form = other_contacts_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy")
+
+ # update the first name of the contact
+ other_contacts_form["other_contacts-0-first_name"] = "Testy2"
+
+ # Submit the updated form
+ other_contacts_form.submit()
+
+ application.refresh_from_db()
+
+ # assert that other contact info is updated, and that a new Contact
+ # is created for the other contact
+ other_contact = application.other_contacts.all()[0]
+ self.assertNotEquals(other_contact_pk, other_contact.id)
+ self.assertEquals("Testy2", other_contact.first_name)
+ # assert that the authorizing official is not updated
+ authorizing_official = application.authorizing_official
+ self.assertEquals("Testy", authorizing_official.first_name)
+
+ def test_edit_authorizing_official_in_place(self):
+ """When you:
+ 1. edit an authorizing official which is not joined to another model,
+ 2. then submit,
+ The application is linked to the existing ao, and the ao updated."""
+
+ # Populate the database with a domain application that
+ # has an authorizing_official (ao)
+ # We'll do it from scratch
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ creator=self.user,
+ status="started",
+ )
+
+ # ao_pk is the initial pk of the Authorizing Official. set it before update
+ # to be able to verify after update that the same Contact object is in place
+ ao_pk = ao.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ ao_page = self.app.get(reverse("application:authorizing_official"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ ao_form = ao_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy")
+
+ # update the first name of the contact
+ ao_form["authorizing_official-first_name"] = "Testy2"
+
+ # Submit the updated form
+ ao_form.submit()
+
+ application.refresh_from_db()
+
+ # assert AO is updated "in place"
+ updated_ao = application.authorizing_official
+ self.assertEquals(ao_pk, updated_ao.id)
+ self.assertEquals("Testy2", updated_ao.first_name)
+
+ def test_edit_authorizing_official_creates_new(self):
+ """When you:
+ 1. edit an existing authorizing official which IS joined to another model,
+ 2. then submit,
+ The application is linked to a new Contact, and the new Contact is updated."""
+
+ # Populate the database with a domain application that
+ # has authorizing official assigned to it, the authorizing offical is also
+ # an other contact initially
+ # We'll do it from scratch
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(ao)
+
+ # ao_pk is the initial pk of the authorizing official. set it before update
+ # to be able to verify after update that the other contact is still in place
+ # and not updated, and that the new ao has a new id
+ ao_pk = ao.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ ao_page = self.app.get(reverse("application:authorizing_official"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ ao_form = ao_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy")
+
+ # update the first name of the contact
+ ao_form["authorizing_official-first_name"] = "Testy2"
+
+ # Submit the updated form
+ ao_form.submit()
+
+ application.refresh_from_db()
+
+ # assert that the other contact is not updated
+ other_contacts = application.other_contacts.all()
+ other_contact = other_contacts[0]
+ self.assertEquals(ao_pk, other_contact.id)
+ self.assertEquals("Testy", other_contact.first_name)
+ # assert that the authorizing official is updated
+ authorizing_official = application.authorizing_official
+ self.assertEquals("Testy2", authorizing_official.first_name)
+
+ def test_edit_submitter_in_place(self):
+ """When you:
+ 1. edit a submitter (your contact) which is not joined to another model,
+ 2. then submit,
+ The application is linked to the existing submitter, and the submitter updated."""
+
+ # Populate the database with a domain application that
+ # has a submitter
+ # We'll do it from scratch
+ you, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ submitter=you,
+ creator=self.user,
+ status="started",
+ )
+
+ # submitter_pk is the initial pk of the submitter. set it before update
+ # to be able to verify after update that the same contact object is in place
+ submitter_pk = you.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ your_contact_page = self.app.get(reverse("application:your_contact"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ your_contact_form = your_contact_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy")
+
+ # update the first name of the contact
+ your_contact_form["your_contact-first_name"] = "Testy2"
+
+ # Submit the updated form
+ your_contact_form.submit()
+
+ application.refresh_from_db()
+
+ updated_submitter = application.submitter
+ self.assertEquals(submitter_pk, updated_submitter.id)
+ self.assertEquals("Testy2", updated_submitter.first_name)
+
+ def test_edit_submitter_creates_new(self):
+ """When you:
+ 1. edit an existing your contact which IS joined to another model,
+ 2. then submit,
+ The application is linked to a new Contact, and the new Contact is updated."""
+
+ # Populate the database with a domain application that
+ # has submitter assigned to it, the submitter is also
+ # an other contact initially
+ # We'll do it from scratch
+ submitter, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(201) 555 5555",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ submitter=submitter,
+ creator=self.user,
+ status="started",
+ )
+ application.other_contacts.add(submitter)
+
+ # submitter_pk is the initial pk of the your contact. set it before update
+ # to be able to verify after update that the other contact is still in place
+ # and not updated, and that the new submitter has a new id
+ submitter_pk = submitter.id
+
+ # prime the form by visiting /edit
+ self.app.get(reverse("edit-application", kwargs={"id": application.pk}))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ your_contact_page = self.app.get(reverse("application:your_contact"))
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ your_contact_form = your_contact_page.forms[0]
+
+ # Minimal check to ensure the form is loaded
+ self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy")
+
+ # update the first name of the contact
+ your_contact_form["your_contact-first_name"] = "Testy2"
+
+ # Submit the updated form
+ your_contact_form.submit()
+
+ application.refresh_from_db()
+
+ # assert that the other contact is not updated
+ other_contacts = application.other_contacts.all()
+ other_contact = other_contacts[0]
+ self.assertEquals(submitter_pk, other_contact.id)
+ self.assertEquals("Testy", other_contact.first_name)
+ # assert that the submitter is updated
+ submitter = application.submitter
+ self.assertEquals("Testy2", submitter.first_name)
+
+ def test_application_about_your_organiztion_interstate(self):
+ """Special districts have to answer an additional question."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ contact_page = type_result.follow()
+
+ self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION])
+
+ def test_application_tribal_government(self):
+ """Tribal organizations have to answer an additional question."""
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.TRIBAL
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+ # the tribal government page comes immediately afterwards
+ self.assertIn("/tribal_government", type_result.headers["Location"])
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ tribal_government_page = type_result.follow()
+
+ # and the step is on the sidebar list.
+ self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT])
+
+ def test_application_ao_dynamic_text(self):
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # ---- TYPE PAGE ----
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "federal"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # ---- FEDERAL BRANCH PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_page = type_result.follow()
+ federal_form = federal_page.forms[0]
+ federal_form["organization_federal-federal_type"] = "executive"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_result = federal_form.submit()
+
+ # ---- ORG CONTACT PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_page = federal_result.follow()
+ org_contact_form = org_contact_page.forms[0]
+ # federal agency so we have to fill in federal_agency
+ org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
+ org_contact_form["organization_contact-organization_name"] = "Testorg"
+ org_contact_form["organization_contact-address_line1"] = "address 1"
+ org_contact_form["organization_contact-address_line2"] = "address 2"
+ org_contact_form["organization_contact-city"] = "NYC"
+ org_contact_form["organization_contact-state_territory"] = "NY"
+ org_contact_form["organization_contact-zipcode"] = "10002"
+ org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_result = org_contact_form.submit()
+
+ # ---- AO CONTACT PAGE ----
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page = org_contact_result.follow()
+ self.assertContains(ao_page, "Executive branch federal agencies")
+
+ # Go back to organization type page and change type
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page.click(str(self.TITLES["organization_type"]), index=0)
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_form["organization_type-organization_type"] = "city"
+ type_result = type_form.submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ election_page = type_result.follow()
+
+ # Go back to AO page and test the dynamic text changed
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page = election_page.click(str(self.TITLES["authorizing_official"]), index=0)
+ self.assertContains(ao_page, "Domain requests from cities")
+
+ def test_application_dotgov_domain_dynamic_text(self):
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ # ---- TYPE PAGE ----
+ type_form = type_page.forms[0]
+ type_form["organization_type-organization_type"] = "federal"
+
+ # test next button
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_result = type_form.submit()
+
+ # ---- FEDERAL BRANCH PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_page = type_result.follow()
+ federal_form = federal_page.forms[0]
+ federal_form["organization_federal-federal_type"] = "executive"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ federal_result = federal_form.submit()
+
+ # ---- ORG CONTACT PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_page = federal_result.follow()
+ org_contact_form = org_contact_page.forms[0]
+ # federal agency so we have to fill in federal_agency
+ org_contact_form["organization_contact-federal_agency"] = "General Services Administration"
+ org_contact_form["organization_contact-organization_name"] = "Testorg"
+ org_contact_form["organization_contact-address_line1"] = "address 1"
+ org_contact_form["organization_contact-address_line2"] = "address 2"
+ org_contact_form["organization_contact-city"] = "NYC"
+ org_contact_form["organization_contact-state_territory"] = "NY"
+ org_contact_form["organization_contact-zipcode"] = "10002"
+ org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ org_contact_result = org_contact_form.submit()
+
+ # ---- AO CONTACT PAGE ----
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page = org_contact_result.follow()
+
+ # ---- AUTHORIZING OFFICIAL PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_page = org_contact_result.follow()
+ ao_form = ao_page.forms[0]
+ ao_form["authorizing_official-first_name"] = "Testy ATO"
+ ao_form["authorizing_official-last_name"] = "Tester ATO"
+ ao_form["authorizing_official-title"] = "Chief Tester"
+ ao_form["authorizing_official-email"] = "testy@town.com"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_result = ao_form.submit()
+
+ # ---- CURRENT SITES PAGE ----
+ # Follow the redirect to the next form page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_page = ao_result.follow()
+ current_sites_form = current_sites_page.forms[0]
+ current_sites_form["current_sites-0-website"] = "www.city.com"
+
+ # test saving the page
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_result = current_sites_form.submit()
+
+ # ---- DOTGOV DOMAIN PAGE ----
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ dotgov_page = current_sites_result.follow()
+
+ self.assertContains(dotgov_page, "medicare.gov")
+
+ # Go back to organization type page and change type
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ dotgov_page.click(str(self.TITLES["organization_type"]), index=0)
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_form["organization_type-organization_type"] = "city"
+ type_result = type_form.submit()
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ election_page = type_result.follow()
+
+ # Go back to dotgov domain page to test the dynamic text changed
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ dotgov_page = election_page.click(str(self.TITLES["dotgov_domain"]), index=0)
+ self.assertContains(dotgov_page, "CityofEudoraKS.gov")
+ self.assertNotContains(dotgov_page, "medicare.gov")
+
+ def test_application_formsets(self):
+ """Users are able to add more than one of some fields."""
+ current_sites_page = self.app.get(reverse("application:current_sites"))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ # fill in the form field
+ current_sites_form = current_sites_page.forms[0]
+ self.assertIn("current_sites-0-website", current_sites_form.fields)
+ self.assertNotIn("current_sites-1-website", current_sites_form.fields)
+ current_sites_form["current_sites-0-website"] = "https://example.com"
+
+ # click "Add another"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_result = current_sites_form.submit("submit_button", value="save")
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ current_sites_form = current_sites_result.follow().forms[0]
+
+ # verify that there are two form fields
+ value = current_sites_form["current_sites-0-website"].value
+ self.assertEqual(value, "https://example.com")
+ self.assertIn("current_sites-1-website", current_sites_form.fields)
+ # and it is correctly referenced in the ManyToOne relationship
+ application = DomainApplication.objects.get() # there's only one
+ self.assertEqual(
+ application.current_websites.filter(website="https://example.com").count(),
+ 1,
+ )
+
+ @skip("WIP")
+ def test_application_edit_restore(self):
+ """
+ Test that a previously saved application is available at the /edit endpoint.
+ """
+ ao, _ = Contact.objects.get_or_create(
+ first_name="Testy",
+ last_name="Tester",
+ title="Chief Tester",
+ email="testy@town.com",
+ phone="(555) 555 5555",
+ )
+ domain, _ = Domain.objects.get_or_create(name="city.gov")
+ alt, _ = Website.objects.get_or_create(website="city1.gov")
+ current, _ = Website.objects.get_or_create(website="city.com")
+ 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",
+ )
+ application, _ = DomainApplication.objects.get_or_create(
+ organization_type="federal",
+ federal_type="executive",
+ purpose="Purpose of the site",
+ anything_else="No",
+ is_policy_acknowledged=True,
+ organization_name="Testorg",
+ address_line1="address 1",
+ state_territory="NY",
+ zipcode="10002",
+ authorizing_official=ao,
+ requested_domain=domain,
+ submitter=you,
+ creator=self.user,
+ )
+ application.other_contacts.add(other)
+ application.current_websites.add(current)
+ application.alternative_domains.add(alt)
+
+ # prime the form by visiting /edit
+ url = reverse("edit-application", kwargs={"id": application.pk})
+ response = self.client.get(url)
+
+ # TODO: this is a sketch of each page in the wizard which needs to be tested
+ # Django does not have tools sufficient for real end to end integration testing
+ # (for example, USWDS moves radio buttons off screen and replaces them with
+ # CSS styled "fakes" -- Django cannot determine if those are visually correct)
+ # -- the best that can/should be done here is to ensure the correct values
+ # are being passed to the templating engine
+
+ url = reverse("application:organization_type")
+ response = self.client.get(url, follow=True)
+ self.assertContains(response, "
")
+ # choices = response.context['wizard']['form']['organization_type'].subwidgets
+ # radio = [ x for x in choices if x.data["value"] == "federal" ][0]
+ # checked = radio.data["selected"]
+ # self.assertTrue(checked)
+
+ # url = reverse("application:organization_federal")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:organization_contact")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:authorizing_official")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:current_sites")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:dotgov_domain")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:purpose")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:your_contact")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:other_contacts")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:other_contacts")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:security_email")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:anything_else")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ # url = reverse("application:requirements")
+ # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # page = self.app.get(url)
+ # self.assertNotContains(page, "VALUE")
+
+ def test_long_org_name_in_application(self):
+ """
+ Make sure the long name is displaying in the application form,
+ org step
+ """
+ intro_page = self.app.get(reverse("application:"))
+ # django-webtest does not handle cookie-based sessions well because it keeps
+ # resetting the session key on each new request, thus destroying the concept
+ # of a "session". We are going to do it manually, saving the session ID here
+ # and then setting the cookie on each request.
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ intro_form = intro_page.forms[0]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ intro_result = intro_form.submit()
+
+ # follow first redirect
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ type_page = intro_result.follow()
+
+ self.assertContains(type_page, "Federal: an agency of the U.S. government")
+
+ def test_submit_modal_no_domain_text_fallback(self):
+ """When user clicks on submit your domain request and the requested domain
+ is null (possible through url direct access to the review page), present
+ fallback copy in the modal's header.
+
+ NOTE: This may be a moot point if we implement a more solid pattern in the
+ future, like not a submit action at all on the review page."""
+
+ review_page = self.app.get(reverse("application:review"))
+ self.assertContains(review_page, "toggle-submit-domain-request")
+ self.assertContains(review_page, "You are about to submit an incomplete request")
+
+
+class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest):
+ def setUp(self):
+ super().setUp()
+ self.app.set_user(self.user.username)
+ self.client.force_login(self.user)
+
+ def test_application_status(self):
+ """Checking application status page"""
+ application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
+ application.save()
+
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ # click the "Manage" link
+ detail_page = home_page.click("Manage", index=0)
+ self.assertContains(detail_page, "city.gov")
+ self.assertContains(detail_page, "city1.gov")
+ self.assertContains(detail_page, "Chief Tester")
+ self.assertContains(detail_page, "testy@town.com")
+ self.assertContains(detail_page, "Admin Tester")
+ self.assertContains(detail_page, "Status:")
+
+ def test_application_status_with_ineligible_user(self):
+ """Checking application status page whith a blocked user.
+ The user should still have access to view."""
+ self.user.status = "ineligible"
+ self.user.save()
+
+ application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
+ application.save()
+
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ # click the "Manage" link
+ detail_page = home_page.click("Manage", index=0)
+ self.assertContains(detail_page, "city.gov")
+ self.assertContains(detail_page, "Chief Tester")
+ self.assertContains(detail_page, "testy@town.com")
+ self.assertContains(detail_page, "Admin Tester")
+ self.assertContains(detail_page, "Status:")
+
+ def test_application_withdraw(self):
+ """Checking application status page"""
+ application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
+ application.save()
+
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ # click the "Manage" link
+ detail_page = home_page.click("Manage", index=0)
+ self.assertContains(detail_page, "city.gov")
+ self.assertContains(detail_page, "city1.gov")
+ self.assertContains(detail_page, "Chief Tester")
+ self.assertContains(detail_page, "testy@town.com")
+ self.assertContains(detail_page, "Admin Tester")
+ self.assertContains(detail_page, "Status:")
+ # click the "Withdraw request" button
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ withdraw_page = detail_page.click("Withdraw request")
+ self.assertContains(withdraw_page, "Withdraw request for")
+ home_page = withdraw_page.click("Withdraw request")
+ # confirm that it has redirected, and the status has been updated to withdrawn
+ self.assertRedirects(
+ home_page,
+ "/",
+ status_code=302,
+ target_status_code=200,
+ fetch_redirect_response=True,
+ )
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "Withdrawn")
+
+ def test_application_withdraw_no_permissions(self):
+ """Can't withdraw applications as a restricted user."""
+ self.user.status = User.RESTRICTED
+ self.user.save()
+ application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
+ application.save()
+
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "city.gov")
+ # click the "Manage" link
+ detail_page = home_page.click("Manage", index=0)
+ self.assertContains(detail_page, "city.gov")
+ self.assertContains(detail_page, "city1.gov")
+ self.assertContains(detail_page, "Chief Tester")
+ self.assertContains(detail_page, "testy@town.com")
+ self.assertContains(detail_page, "Admin Tester")
+ self.assertContains(detail_page, "Status:")
+ # Restricted user trying to withdraw results in 403 error
+ with less_console_noise():
+ for url_name in [
+ "application-withdraw-confirmation",
+ "application-withdrawn",
+ ]:
+ with self.subTest(url_name=url_name):
+ page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
+ self.assertEqual(page.status_code, 403)
+
+ def test_application_status_no_permissions(self):
+ """Can't access applications without being the creator."""
+ application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
+ other_user = User()
+ other_user.save()
+ application.creator = other_user
+ application.save()
+
+ # PermissionDeniedErrors make lots of noise in test output
+ with less_console_noise():
+ for url_name in [
+ "application-status",
+ "application-withdraw-confirmation",
+ "application-withdrawn",
+ ]:
+ with self.subTest(url_name=url_name):
+ page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
+ self.assertEqual(page.status_code, 403)
+
+ def test_approved_application_not_in_active_requests(self):
+ """An approved application is not shown in the Active
+ Requests table on home.html."""
+ application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED, user=self.user)
+ application.save()
+
+ home_page = self.app.get("/")
+ # This works in our test environment because creating
+ # an approved application here does not generate a
+ # domain object, so we do not expect to see 'city.gov'
+ # in either the Domains or Requests tables.
+ self.assertNotContains(home_page, "city.gov")
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
new file mode 100644
index 000000000..c9422e700
--- /dev/null
+++ b/src/registrar/tests/test_views_domain.py
@@ -0,0 +1,1436 @@
+from unittest import skip
+from unittest.mock import MagicMock, ANY, patch
+
+from django.conf import settings
+from django.urls import reverse
+from django.contrib.auth import get_user_model
+
+from .common import MockSESClient, create_user # type: ignore
+from django_webtest import WebTest # type: ignore
+import boto3_mocking # type: ignore
+
+from registrar.utility.errors import (
+ NameserverError,
+ NameserverErrorCodes,
+ SecurityEmailError,
+ SecurityEmailErrorCodes,
+ GenericError,
+ GenericErrorCodes,
+ DsDataError,
+ DsDataErrorCodes,
+)
+
+from registrar.models import (
+ DomainApplication,
+ Domain,
+ DomainInformation,
+ DomainInvitation,
+ Contact,
+ PublicContact,
+ Host,
+ HostIP,
+ UserDomainRole,
+ User,
+)
+from datetime import date, datetime, timedelta
+from django.utils import timezone
+
+from .common import less_console_noise
+from .test_views import TestWithUser
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class TestWithDomainPermissions(TestWithUser):
+ def setUp(self):
+ super().setUp()
+ self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ self.domain_with_ip, _ = Domain.objects.get_or_create(name="nameserverwithip.gov")
+ self.domain_just_nameserver, _ = Domain.objects.get_or_create(name="justnameserver.com")
+ self.domain_no_information, _ = Domain.objects.get_or_create(name="noinformation.gov")
+ self.domain_on_hold, _ = Domain.objects.get_or_create(
+ name="on-hold.gov",
+ state=Domain.State.ON_HOLD,
+ expiration_date=timezone.make_aware(
+ datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
+ ),
+ )
+ self.domain_deleted, _ = Domain.objects.get_or_create(
+ name="deleted.gov",
+ state=Domain.State.DELETED,
+ expiration_date=timezone.make_aware(
+ datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
+ ),
+ )
+
+ self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
+ # We could simply use domain (igorville) but this will be more readable in tests
+ # that inherit this setUp
+ self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov")
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dsdata)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_multdsdata)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dnssec_none)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_with_ip)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_just_nameserver)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_on_hold)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_deleted)
+
+ self.role, _ = UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
+ )
+
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.MANAGER
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user,
+ domain=self.domain_multdsdata,
+ role=UserDomainRole.Roles.MANAGER,
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user,
+ domain=self.domain_dnssec_none,
+ role=UserDomainRole.Roles.MANAGER,
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user,
+ domain=self.domain_with_ip,
+ role=UserDomainRole.Roles.MANAGER,
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user,
+ domain=self.domain_just_nameserver,
+ role=UserDomainRole.Roles.MANAGER,
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_on_hold, role=UserDomainRole.Roles.MANAGER
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_deleted, role=UserDomainRole.Roles.MANAGER
+ )
+
+ def tearDown(self):
+ try:
+ UserDomainRole.objects.all().delete()
+ if hasattr(self.domain, "contacts"):
+ self.domain.contacts.all().delete()
+ DomainApplication.objects.all().delete()
+ DomainInformation.objects.all().delete()
+ PublicContact.objects.all().delete()
+ HostIP.objects.all().delete()
+ Host.objects.all().delete()
+ Domain.objects.all().delete()
+ UserDomainRole.objects.all().delete()
+ except ValueError: # pass if already deleted
+ pass
+ super().tearDown()
+
+
+class TestDomainPermissions(TestWithDomainPermissions):
+ def test_not_logged_in(self):
+ """Not logged in gets a redirect to Login."""
+ for view_name in [
+ "domain",
+ "domain-users",
+ "domain-users-add",
+ "domain-dns-nameservers",
+ "domain-org-name-address",
+ "domain-authorizing-official",
+ "domain-your-contact-information",
+ "domain-security-email",
+ ]:
+ with self.subTest(view_name=view_name):
+ response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id}))
+ self.assertEqual(response.status_code, 302)
+
+ def test_no_domain_role(self):
+ """Logged in but no role gets 403 Forbidden."""
+ self.client.force_login(self.user)
+ self.role.delete() # user no longer has a role on this domain
+
+ for view_name in [
+ "domain",
+ "domain-users",
+ "domain-users-add",
+ "domain-dns-nameservers",
+ "domain-org-name-address",
+ "domain-authorizing-official",
+ "domain-your-contact-information",
+ "domain-security-email",
+ ]:
+ with self.subTest(view_name=view_name):
+ with less_console_noise():
+ response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id}))
+ self.assertEqual(response.status_code, 403)
+
+ def test_domain_pages_blocked_for_on_hold_and_deleted(self):
+ """Test that the domain pages are blocked for on hold and deleted domains"""
+
+ self.client.force_login(self.user)
+ for view_name in [
+ "domain-users",
+ "domain-users-add",
+ "domain-dns",
+ "domain-dns-nameservers",
+ "domain-dns-dnssec",
+ "domain-dns-dnssec-dsdata",
+ "domain-org-name-address",
+ "domain-authorizing-official",
+ "domain-your-contact-information",
+ "domain-security-email",
+ ]:
+ for domain in [
+ self.domain_on_hold,
+ self.domain_deleted,
+ ]:
+ with self.subTest(view_name=view_name, domain=domain):
+ with less_console_noise():
+ response = self.client.get(reverse(view_name, kwargs={"pk": domain.id}))
+ self.assertEqual(response.status_code, 403)
+
+
+class TestDomainOverview(TestWithDomainPermissions, WebTest):
+ def setUp(self):
+ super().setUp()
+ self.app.set_user(self.user.username)
+ self.client.force_login(self.user)
+
+
+class TestDomainDetail(TestDomainOverview):
+ @skip("Assertion broke for no reason, why? Need to fix")
+ def test_domain_detail_link_works(self):
+ home_page = self.app.get("/")
+ logger.info(f"This is the value of home_page: {home_page}")
+ self.assertContains(home_page, "igorville.gov")
+ # click the "Edit" link
+ detail_page = home_page.click("Manage", index=0)
+ self.assertContains(detail_page, "igorville.gov")
+ self.assertContains(detail_page, "Status")
+
+ def test_unknown_domain_does_not_show_as_expired_on_homepage(self):
+ """An UNKNOWN domain does not show as expired on the homepage.
+ It shows as 'DNS needed'"""
+ # At the time of this test's writing, there are 6 UNKNOWN domains inherited
+ # from constructors. Let's reset.
+ with less_console_noise():
+ Domain.objects.all().delete()
+ UserDomainRole.objects.all().delete()
+ self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ home_page = self.app.get("/")
+ self.assertNotContains(home_page, "igorville.gov")
+ self.role, _ = UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
+ )
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "igorville.gov")
+ igorville = Domain.objects.get(name="igorville.gov")
+ self.assertEquals(igorville.state, Domain.State.UNKNOWN)
+ self.assertNotContains(home_page, "Expired")
+ self.assertContains(home_page, "DNS needed")
+
+ def test_unknown_domain_does_not_show_as_expired_on_detail_page(self):
+ """An UNKNOWN domain does not show as expired on the detail page.
+ It shows as 'DNS needed'"""
+ # At the time of this test's writing, there are 6 UNKNOWN domains inherited
+ # from constructors. Let's reset.
+ with less_console_noise():
+ Domain.objects.all().delete()
+ UserDomainRole.objects.all().delete()
+
+ self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+ self.role, _ = UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
+ )
+
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "igorville.gov")
+ igorville = Domain.objects.get(name="igorville.gov")
+ self.assertEquals(igorville.state, Domain.State.UNKNOWN)
+ detail_page = home_page.click("Manage", index=0)
+ self.assertNotContains(detail_page, "Expired")
+
+ self.assertContains(detail_page, "DNS needed")
+
+ def test_domain_detail_blocked_for_ineligible_user(self):
+ """We could easily duplicate this test for all domain management
+ views, but a single url test should be solid enough since all domain
+ management pages share the same permissions class"""
+ with less_console_noise():
+ self.user.status = User.RESTRICTED
+ self.user.save()
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "igorville.gov")
+ response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
+ self.assertEqual(response.status_code, 403)
+
+ def test_domain_detail_allowed_for_on_hold(self):
+ """Test that the domain overview page displays for on hold domain"""
+ with less_console_noise():
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "on-hold.gov")
+
+ # View domain overview page
+ detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_on_hold.id}))
+ self.assertNotContains(detail_page, "Edit")
+
+ def test_domain_detail_see_just_nameserver(self):
+ with less_console_noise():
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "justnameserver.com")
+
+ # View nameserver on Domain Overview page
+ detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_just_nameserver.id}))
+
+ self.assertContains(detail_page, "justnameserver.com")
+ self.assertContains(detail_page, "ns1.justnameserver.com")
+ self.assertContains(detail_page, "ns2.justnameserver.com")
+
+ def test_domain_detail_see_nameserver_and_ip(self):
+ with less_console_noise():
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "nameserverwithip.gov")
+
+ # View nameserver on Domain Overview page
+ detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_with_ip.id}))
+
+ self.assertContains(detail_page, "nameserverwithip.gov")
+
+ self.assertContains(detail_page, "ns1.nameserverwithip.gov")
+ self.assertContains(detail_page, "ns2.nameserverwithip.gov")
+ self.assertContains(detail_page, "ns3.nameserverwithip.gov")
+ # Splitting IP addresses bc there is odd whitespace and can't strip text
+ self.assertContains(detail_page, "(1.2.3.4,")
+ self.assertContains(detail_page, "2.3.4.5)")
+
+ def test_domain_detail_with_no_information_or_application(self):
+ """Test that domain management page returns 200 and displays error
+ when no domain information or domain application exist"""
+ with less_console_noise():
+ # have to use staff user for this test
+ staff_user = create_user()
+ # staff_user.save()
+ self.client.force_login(staff_user)
+
+ # need to set the analyst_action and analyst_action_location
+ # in the session to emulate user clicking Manage Domain
+ # in the admin interface
+ session = self.client.session
+ session["analyst_action"] = "foo"
+ session["analyst_action_location"] = self.domain_no_information.id
+ session.save()
+
+ detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_no_information.id}))
+
+ self.assertContains(detail_page, "noinformation.gov")
+ self.assertContains(detail_page, "Domain missing domain information")
+
+
+class TestDomainManagers(TestDomainOverview):
+ def tearDown(self):
+ """Ensure that the user has its original permissions"""
+ super().tearDown()
+ self.user.is_staff = False
+ self.user.save()
+
+ def test_domain_managers(self):
+ response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id}))
+ self.assertContains(response, "Domain managers")
+
+ def test_domain_managers_add_link(self):
+ """Button to get to user add page works."""
+ management_page = self.app.get(reverse("domain-users", kwargs={"pk": self.domain.id}))
+ add_page = management_page.click("Add a domain manager")
+ self.assertContains(add_page, "Add a domain manager")
+
+ def test_domain_user_add(self):
+ response = self.client.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ self.assertContains(response, "Add a domain manager")
+
+ @boto3_mocking.patching
+ def test_domain_user_add_form(self):
+ """Adding an existing user works."""
+ other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov")
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ add_page.form["email"] = "mayor@igorville.gov"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ success_result = add_page.form.submit()
+
+ self.assertEqual(success_result.status_code, 302)
+ self.assertEqual(
+ success_result["Location"],
+ reverse("domain-users", kwargs={"pk": self.domain.id}),
+ )
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ success_page = success_result.follow()
+ self.assertContains(success_page, "mayor@igorville.gov")
+
+ @boto3_mocking.patching
+ def test_domain_invitation_created(self):
+ """Add user on a nonexistent email creates an invitation.
+
+ Adding a non-existent user sends an email as a side-effect, so mock
+ out the boto3 SES email sending here.
+ """
+ # make sure there is no user with this email
+ email_address = "mayor@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ success_result = add_page.form.submit()
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ success_page = success_result.follow()
+
+ self.assertContains(success_page, email_address)
+ self.assertContains(success_page, "Cancel") # link to cancel invitation
+ self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists())
+
+ @boto3_mocking.patching
+ def test_domain_invitation_created_for_caps_email(self):
+ """Add user on a nonexistent email with CAPS creates an invitation to lowercase email.
+
+ Adding a non-existent user sends an email as a side-effect, so mock
+ out the boto3 SES email sending here.
+ """
+ # make sure there is no user with this email
+ email_address = "mayor@igorville.gov"
+ caps_email_address = "MAYOR@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = caps_email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ success_result = add_page.form.submit()
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ success_page = success_result.follow()
+
+ self.assertContains(success_page, email_address)
+ self.assertContains(success_page, "Cancel") # link to cancel invitation
+ self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists())
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_sent(self):
+ """Inviting a non-existent user sends them an email."""
+ # make sure there is no user with this email
+ email_address = "mayor@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit()
+
+ # check the mock instance to see if `send_email` was called right
+ mock_client_instance.send_email.assert_called_once_with(
+ FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
+ Destination={"ToAddresses": [email_address]},
+ Content=ANY,
+ )
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_has_email_as_requestor_non_existent(self):
+ """Inviting a non existent user sends them an email, with email as the name."""
+ # make sure there is no user with this email
+ email_address = "mayor@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
+
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit()
+
+ # check the mock instance to see if `send_email` was called right
+ mock_client_instance.send_email.assert_called_once_with(
+ FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
+ Destination={"ToAddresses": [email_address]},
+ Content=ANY,
+ )
+
+ # Check the arguments passed to send_email method
+ _, kwargs = mock_client_instance.send_email.call_args
+
+ # Extract the email content, and check that the message is as we expect
+ email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
+ self.assertIn("info@example.com", email_content)
+
+ # Check that the requestors first/last name do not exist
+ self.assertNotIn("First", email_content)
+ self.assertNotIn("Last", email_content)
+ self.assertNotIn("First Last", email_content)
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_has_email_as_requestor(self):
+ """Inviting a user sends them an email, with email as the name."""
+ # Create a fake user object
+ email_address = "mayor@igorville.gov"
+ User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
+
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit()
+
+ # check the mock instance to see if `send_email` was called right
+ mock_client_instance.send_email.assert_called_once_with(
+ FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
+ Destination={"ToAddresses": [email_address]},
+ Content=ANY,
+ )
+
+ # Check the arguments passed to send_email method
+ _, kwargs = mock_client_instance.send_email.call_args
+
+ # Extract the email content, and check that the message is as we expect
+ email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
+ self.assertIn("info@example.com", email_content)
+
+ # Check that the requestors first/last name do not exist
+ self.assertNotIn("First", email_content)
+ self.assertNotIn("Last", email_content)
+ self.assertNotIn("First Last", email_content)
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_has_email_as_requestor_staff(self):
+ """Inviting a user sends them an email, with email as the name."""
+ # Create a fake user object
+ email_address = "mayor@igorville.gov"
+ User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
+
+ # Make sure the user is staff
+ self.user.is_staff = True
+ self.user.save()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+ mock_client_instance = mock_client.return_value
+
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit()
+
+ # check the mock instance to see if `send_email` was called right
+ mock_client_instance.send_email.assert_called_once_with(
+ FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
+ Destination={"ToAddresses": [email_address]},
+ Content=ANY,
+ )
+
+ # Check the arguments passed to send_email method
+ _, kwargs = mock_client_instance.send_email.call_args
+
+ # Extract the email content, and check that the message is as we expect
+ email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
+ self.assertIn("help@get.gov", email_content)
+
+ # Check that the requestors first/last name do not exist
+ self.assertNotIn("First", email_content)
+ self.assertNotIn("Last", email_content)
+ self.assertNotIn("First Last", email_content)
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_displays_error_non_existent(self):
+ """Inviting a non existent user sends them an email, with email as the name."""
+ # make sure there is no user with this email
+ email_address = "mayor@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ # Give the user who is sending the email an invalid email address
+ self.user.email = ""
+ self.user.save()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+ mock_error_message = MagicMock()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with patch("django.contrib.messages.error") as mock_error_message:
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit().follow()
+
+ expected_message_content = "Can't send invitation email. No email is associated with your account."
+
+ # Grab the message content
+ returned_error_message = mock_error_message.call_args[0][1]
+
+ # Check that the message content is what we expect
+ self.assertEqual(expected_message_content, returned_error_message)
+
+ @boto3_mocking.patching
+ def test_domain_invitation_email_displays_error(self):
+ """When the requesting user has no email, an error is displayed"""
+ # make sure there is no user with this email
+ # Create a fake user object
+ email_address = "mayor@igorville.gov"
+ User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com")
+
+ # Give the user who is sending the email an invalid email address
+ self.user.email = ""
+ self.user.save()
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ mock_client = MagicMock()
+
+ mock_error_message = MagicMock()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with patch("django.contrib.messages.error") as mock_error_message:
+ with less_console_noise():
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ add_page.form.submit().follow()
+
+ expected_message_content = "Can't send invitation email. No email is associated with your account."
+
+ # Grab the message content
+ returned_error_message = mock_error_message.call_args[0][1]
+
+ # Check that the message content is what we expect
+ self.assertEqual(expected_message_content, returned_error_message)
+
+ def test_domain_invitation_cancel(self):
+ """Posting to the delete view deletes an invitation."""
+ email_address = "mayor@igorville.gov"
+ invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
+ mock_client = MockSESClient()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id}))
+ mock_client.EMAILS_SENT.clear()
+ with self.assertRaises(DomainInvitation.DoesNotExist):
+ DomainInvitation.objects.get(id=invitation.id)
+
+ def test_domain_invitation_cancel_no_permissions(self):
+ """Posting to the delete view as a different user should fail."""
+ email_address = "mayor@igorville.gov"
+ invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
+
+ other_user = User()
+ other_user.save()
+ self.client.force_login(other_user)
+ mock_client = MagicMock()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise(): # permission denied makes console errors
+ result = self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id}))
+
+ self.assertEqual(result.status_code, 403)
+
+ @boto3_mocking.patching
+ def test_domain_invitation_flow(self):
+ """Send an invitation to a new user, log in and load the dashboard."""
+ email_address = "mayor@igorville.gov"
+ User.objects.filter(email=email_address).delete()
+
+ add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
+
+ self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
+
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ add_page.form["email"] = email_address
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+
+ mock_client = MagicMock()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise():
+ add_page.form.submit()
+
+ # user was invited, create them
+ new_user = User.objects.create(username=email_address, email=email_address)
+ # log them in to `self.app`
+ self.app.set_user(new_user.username)
+ # and manually call the on each login callback
+ new_user.on_each_login()
+
+ # Now load the home page and make sure our domain appears there
+ home_page = self.app.get(reverse("home"))
+ self.assertContains(home_page, self.domain.name)
+
+
+class TestDomainNameservers(TestDomainOverview):
+ def test_domain_nameservers(self):
+ """Can load domain's nameservers page."""
+ page = self.client.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "DNS name servers")
+
+ def test_domain_nameservers_form_submit_one_nameserver(self):
+ """Nameserver form submitted with one nameserver throws error.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form with only one nameserver, should error
+ # regarding required fields
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. form requires a minimum of 2 name servers
+ self.assertContains(
+ result,
+ "At least two name servers are required.",
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_subdomain_missing_ip(self):
+ """Nameserver form catches missing ip error on subdomain.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-1-server"] = "ns2.igorville.gov"
+
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. subdomain missing an ip
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.MISSING_IP)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_missing_host(self):
+ """Nameserver form catches error when host is missing.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-1-ip"] = "127.0.0.1"
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. nameserver has ip but missing host
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.MISSING_HOST)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_duplicate_host(self):
+ """Nameserver form catches error when host is duplicated.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form with duplicate host names of fake.host.com
+ nameservers_page.form["form-0-ip"] = ""
+ nameservers_page.form["form-1-server"] = "fake.host.com"
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. remove duplicate entry
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.DUPLICATE_HOST)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_whitespace(self):
+ """Nameserver form removes whitespace from ip.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameserver1 = "ns1.igorville.gov"
+ nameserver2 = "ns2.igorville.gov"
+ valid_ip = "1.1. 1.1"
+ # initial nameservers page has one server with two ips
+ # have to throw an error in order to test that the whitespace has been stripped from ip
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without one host and an ip with whitespace
+ nameservers_page.form["form-0-server"] = nameserver1
+ nameservers_page.form["form-1-ip"] = valid_ip
+ nameservers_page.form["form-1-server"] = nameserver2
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an ip address which has been stripped of whitespace,
+ # response should be a 302 to success page
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}),
+ )
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ page = result.follow()
+ # in the event of a generic nameserver error from registry error, there will be a 302
+ # with an error message displayed, so need to follow 302 and test for success message
+ self.assertContains(page, "The name servers for this domain have been updated")
+
+ def test_domain_nameservers_form_submit_glue_record_not_allowed(self):
+ """Nameserver form catches error when IP is present
+ but host not subdomain.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameserver1 = "ns1.igorville.gov"
+ nameserver2 = "ns2.igorville.com"
+ valid_ip = "127.0.0.1"
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-0-server"] = nameserver1
+ nameservers_page.form["form-1-server"] = nameserver2
+ nameservers_page.form["form-1-ip"] = valid_ip
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. nameserver has ip but missing host
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.GLUE_RECORD_NOT_ALLOWED)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_invalid_ip(self):
+ """Nameserver form catches invalid IP on submission.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameserver = "ns2.igorville.gov"
+ invalid_ip = "123"
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-1-server"] = nameserver
+ nameservers_page.form["form-1-ip"] = invalid_ip
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. nameserver has ip but missing host
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.INVALID_IP, nameserver=nameserver)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submit_invalid_host(self):
+ """Nameserver form catches invalid host on submission.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameserver = "invalid-nameserver.gov"
+ valid_ip = "123.2.45.111"
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-1-server"] = nameserver
+ nameservers_page.form["form-1-ip"] = valid_ip
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the required field. nameserver has invalid host
+ self.assertContains(
+ result,
+ str(NameserverError(code=NameserverErrorCodes.INVALID_HOST, nameserver=nameserver)),
+ count=2,
+ status_code=200,
+ )
+
+ def test_domain_nameservers_form_submits_successfully(self):
+ """Nameserver form submits successfully with valid input.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameserver1 = "ns1.igorville.gov"
+ nameserver2 = "ns2.igorville.gov"
+ valid_ip = "127.0.0.1"
+ # initial nameservers page has one server with two ips
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # attempt to submit the form without two hosts, both subdomains,
+ # only one has ips
+ nameservers_page.form["form-0-server"] = nameserver1
+ nameservers_page.form["form-1-server"] = nameserver2
+ nameservers_page.form["form-1-ip"] = valid_ip
+ with less_console_noise(): # swallow log warning message
+ result = nameservers_page.form.submit()
+ # form submission was a successful post, response should be a 302
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}),
+ )
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ page = result.follow()
+ self.assertContains(page, "The name servers for this domain have been updated")
+
+ def test_domain_nameservers_form_invalid(self):
+ """Nameserver form does not submit with invalid data.
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ nameservers_page.form["form-0-server"] = ""
+ with less_console_noise(): # swallow logged warning message
+ result = nameservers_page.form.submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears four times, twice at the top of the page,
+ # once around each required field.
+ self.assertContains(
+ result,
+ "At least two name servers are required.",
+ count=4,
+ status_code=200,
+ )
+
+
+class TestDomainAuthorizingOfficial(TestDomainOverview):
+ def test_domain_authorizing_official(self):
+ """Can load domain's authorizing official page."""
+ page = self.client.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
+ # once on the sidebar, once in the title
+ self.assertContains(page, "Authorizing official", count=2)
+
+ def test_domain_authorizing_official_content(self):
+ """Authorizing official information appears on the page."""
+ self.domain_information.authorizing_official = Contact(first_name="Testy")
+ self.domain_information.authorizing_official.save()
+ self.domain_information.save()
+ page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Testy")
+
+ def test_domain_edit_authorizing_official_in_place(self):
+ """When editing an authorizing official for domain information and AO is not
+ joined to any other objects"""
+ self.domain_information.authorizing_official = Contact(
+ first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov"
+ )
+ self.domain_information.authorizing_official.save()
+ self.domain_information.save()
+ ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_form = ao_page.forms[0]
+ self.assertEqual(ao_form["first_name"].value, "Testy")
+ ao_form["first_name"] = "Testy2"
+ # ao_pk is the initial pk of the authorizing official. set it before update
+ # to be able to verify after update that the same contact object is in place
+ ao_pk = self.domain_information.authorizing_official.id
+ ao_form.submit()
+
+ # refresh domain information
+ self.domain_information.refresh_from_db()
+ self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name)
+ self.assertEqual(ao_pk, self.domain_information.authorizing_official.id)
+
+ def test_domain_edit_authorizing_official_creates_new(self):
+ """When editing an authorizing official for domain information and AO IS
+ joined to another object"""
+ # set AO and Other Contact to the same Contact object
+ self.domain_information.authorizing_official = Contact(
+ first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov"
+ )
+ self.domain_information.authorizing_official.save()
+ self.domain_information.save()
+ self.domain_information.other_contacts.add(self.domain_information.authorizing_official)
+ self.domain_information.save()
+ # load the Authorizing Official in the web form
+ ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ ao_form = ao_page.forms[0]
+ # verify the first name is "Testy" and then change it to "Testy2"
+ self.assertEqual(ao_form["first_name"].value, "Testy")
+ ao_form["first_name"] = "Testy2"
+ # ao_pk is the initial pk of the authorizing official. set it before update
+ # to be able to verify after update that the same contact object is in place
+ ao_pk = self.domain_information.authorizing_official.id
+ ao_form.submit()
+
+ # refresh domain information
+ self.domain_information.refresh_from_db()
+ # assert that AO information is updated, and that the AO is a new Contact
+ self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name)
+ self.assertNotEqual(ao_pk, self.domain_information.authorizing_official.id)
+ # assert that the Other Contact information is not updated and that the Other Contact
+ # is the original Contact object
+ other_contact = self.domain_information.other_contacts.all()[0]
+ self.assertEqual("Testy", other_contact.first_name)
+ self.assertEqual(ao_pk, other_contact.id)
+
+
+class TestDomainOrganization(TestDomainOverview):
+ def test_domain_org_name_address(self):
+ """Can load domain's org name and mailing address page."""
+ page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
+ # once on the sidebar, once in the page title, once as H1
+ self.assertContains(page, "Organization name and mailing address", count=3)
+
+ def test_domain_org_name_address_content(self):
+ """Org name and address information appears on the page."""
+ self.domain_information.organization_name = "Town of Igorville"
+ self.domain_information.save()
+ page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Town of Igorville")
+
+ def test_domain_org_name_address_form(self):
+ """Submitting changes works on the org name address page."""
+ self.domain_information.organization_name = "Town of Igorville"
+ self.domain_information.save()
+ org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+
+ org_name_page.form["organization_name"] = "Not igorville"
+ org_name_page.form["city"] = "Faketown"
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ success_result_page = org_name_page.form.submit()
+ self.assertEqual(success_result_page.status_code, 200)
+
+ self.assertContains(success_result_page, "Not igorville")
+ self.assertContains(success_result_page, "Faketown")
+
+
+class TestDomainContactInformation(TestDomainOverview):
+ def test_domain_your_contact_information(self):
+ """Can load domain's your contact information page."""
+ page = self.client.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Your contact information")
+
+ def test_domain_your_contact_information_content(self):
+ """Logged-in user's contact information appears on the page."""
+ self.user.contact.first_name = "Testy"
+ self.user.contact.save()
+ page = self.app.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Testy")
+
+
+class TestDomainSecurityEmail(TestDomainOverview):
+ def test_domain_security_email_existing_security_contact(self):
+ """Can load domain's security email page."""
+ with less_console_noise():
+ self.mockSendPatch = patch("registrar.models.domain.registry.send")
+ self.mockedSendFunction = self.mockSendPatch.start()
+ self.mockedSendFunction.side_effect = self.mockSend
+
+ domain_contact, _ = Domain.objects.get_or_create(name="freeman.gov")
+ # Add current user to this domain
+ _ = UserDomainRole(user=self.user, domain=domain_contact, role="admin").save()
+ page = self.client.get(reverse("domain-security-email", kwargs={"pk": domain_contact.id}))
+
+ # Loads correctly
+ self.assertContains(page, "Security email")
+ self.assertContains(page, "security@mail.gov")
+ self.mockSendPatch.stop()
+
+ def test_domain_security_email_no_security_contact(self):
+ """Loads a domain with no defined security email.
+ We should not show the default."""
+ with less_console_noise():
+ self.mockSendPatch = patch("registrar.models.domain.registry.send")
+ self.mockedSendFunction = self.mockSendPatch.start()
+ self.mockedSendFunction.side_effect = self.mockSend
+
+ page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
+
+ # Loads correctly
+ self.assertContains(page, "Security email")
+ self.assertNotContains(page, "dotgov@cisa.dhs.gov")
+ self.mockSendPatch.stop()
+
+ def test_domain_security_email(self):
+ """Can load domain's security email page."""
+ with less_console_noise():
+ page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Security email")
+
+ def test_domain_security_email_form(self):
+ """Adding a security email works.
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ with less_console_noise():
+ security_email_page = self.app.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ security_email_page.form["security_email"] = "mayor@igorville.gov"
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ mock_client = MagicMock()
+ with boto3_mocking.clients.handler_for("sesv2", mock_client):
+ with less_console_noise(): # swallow log warning message
+ result = security_email_page.form.submit()
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-security-email", kwargs={"pk": self.domain.id}),
+ )
+
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ success_page = result.follow()
+ self.assertContains(success_page, "The security email for this domain has been updated")
+
+ def test_domain_security_email_form_messages(self):
+ """
+ Test against the success and error messages that are defined in the view
+ """
+ with less_console_noise():
+ p = "adminpass"
+ self.client.login(username="superuser", password=p)
+ form_data_registry_error = {
+ "security_email": "test@failCreate.gov",
+ }
+ form_data_contact_error = {
+ "security_email": "test@contactError.gov",
+ }
+ form_data_success = {
+ "security_email": "test@something.gov",
+ }
+ test_cases = [
+ (
+ "RegistryError",
+ form_data_registry_error,
+ str(GenericError(code=GenericErrorCodes.CANNOT_CONTACT_REGISTRY)),
+ ),
+ (
+ "ContactError",
+ form_data_contact_error,
+ str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)),
+ ),
+ (
+ "RegistrySuccess",
+ form_data_success,
+ "The security email for this domain has been updated.",
+ ),
+ # Add more test cases with different scenarios here
+ ]
+ for test_name, data, expected_message in test_cases:
+ response = self.client.post(
+ reverse("domain-security-email", kwargs={"pk": self.domain.id}),
+ data=data,
+ follow=True,
+ )
+ # Check the response status code, content, or any other relevant assertions
+ self.assertEqual(response.status_code, 200)
+ # Check if the expected message tag is set
+ if test_name == "RegistryError" or test_name == "ContactError":
+ message_tag = "error"
+ elif test_name == "RegistrySuccess":
+ message_tag = "success"
+ else:
+ # Handle other cases if needed
+ message_tag = "info" # Change to the appropriate default
+ # Check the message tag
+ messages = list(response.context["messages"])
+ self.assertEqual(len(messages), 1)
+ message = messages[0]
+ self.assertEqual(message.tags, message_tag)
+ self.assertEqual(message.message.strip(), expected_message.strip())
+
+ def test_domain_overview_blocked_for_ineligible_user(self):
+ """We could easily duplicate this test for all domain management
+ views, but a single url test should be solid enough since all domain
+ management pages share the same permissions class"""
+ self.user.status = User.RESTRICTED
+ self.user.save()
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "igorville.gov")
+ with less_console_noise():
+ response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
+ self.assertEqual(response.status_code, 403)
+
+
+class TestDomainDNSSEC(TestDomainOverview):
+
+ """MockEPPLib is already inherited."""
+
+ def test_dnssec_page_refreshes_enable_button(self):
+ """DNSSEC overview page loads when domain has no DNSSEC data
+ and shows a 'Enable DNSSEC' button."""
+
+ page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}))
+ self.assertContains(page, "Enable DNSSEC")
+
+ def test_dnssec_page_loads_with_data_in_domain(self):
+ """DNSSEC overview page loads when domain has DNSSEC data
+ and the template contains a button to disable DNSSEC."""
+
+ page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id}))
+ self.assertContains(page, "Disable DNSSEC")
+
+ # Prepare the data for the POST request
+ post_data = {
+ "disable_dnssec": "Disable DNSSEC",
+ }
+ updated_page = self.client.post(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}),
+ post_data,
+ follow=True,
+ )
+
+ self.assertEqual(updated_page.status_code, 200)
+
+ self.assertContains(updated_page, "Enable DNSSEC")
+
+ def test_ds_form_loads_with_no_domain_data(self):
+ """DNSSEC Add DS data page loads when there is no
+ domain DNSSEC data and shows a button to Add new record"""
+
+ page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id}))
+ self.assertContains(page, "You have no DS data added")
+ self.assertContains(page, "Add new record")
+
+ def test_ds_form_loads_with_ds_data(self):
+ """DNSSEC Add DS data page loads when there is
+ domain DNSSEC DS data and shows the data"""
+
+ page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ self.assertContains(page, "DS data record 1")
+
+ def test_ds_data_form_modal(self):
+ """When user clicks on save, a modal pops up."""
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ # Assert that a hidden trigger for the modal does not exist.
+ # This hidden trigger will pop on the page when certain condition are met:
+ # 1) Initial form contained DS data, 2) All data is deleted and form is
+ # submitted.
+ self.assertNotContains(add_data_page, "Trigger Disable DNSSEC Modal")
+ # Simulate a delete all data
+ form_data = {}
+ response = self.client.post(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}),
+ data=form_data,
+ )
+ self.assertEqual(response.status_code, 200) # Adjust status code as needed
+ # Now check to see whether the JS trigger for the modal is present on the page
+ self.assertContains(response, "Trigger Disable DNSSEC Modal")
+
+ def test_ds_data_form_submits(self):
+ """DS data form submits successfully
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ with less_console_noise(): # swallow log warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post, response should be a redirect
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}),
+ )
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ page = result.follow()
+ self.assertContains(page, "The DS data records for this domain have been updated.")
+
+ def test_ds_data_form_invalid(self):
+ """DS data form errors with invalid data (missing required fields)
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # all four form fields are required, so will test with each blank
+ add_data_page.forms[0]["form-0-key_tag"] = ""
+ add_data_page.forms[0]["form-0-algorithm"] = ""
+ add_data_page.forms[0]["form-0-digest_type"] = ""
+ add_data_page.forms[0]["form-0-digest"] = ""
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(result, "Key tag is required", count=2, status_code=200)
+ self.assertContains(result, "Algorithm is required", count=2, status_code=200)
+ self.assertContains(result, "Digest type is required", count=2, status_code=200)
+ self.assertContains(result, "Digest is required", count=2, status_code=200)
+
+ def test_ds_data_form_invalid_keytag(self):
+ """DS data form errors with invalid data (key tag too large)
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-key_tag"] = "65536" # > 65535
+ add_data_page.forms[0]["form-0-algorithm"] = ""
+ add_data_page.forms[0]["form-0-digest_type"] = ""
+ add_data_page.forms[0]["form-0-digest"] = ""
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(
+ result, str(DsDataError(code=DsDataErrorCodes.INVALID_KEYTAG_SIZE)), count=2, status_code=200
+ )
+
+ def test_ds_data_form_invalid_digest_chars(self):
+ """DS data form errors with invalid data (digest contains non hexadecimal chars)
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-key_tag"] = "1234"
+ add_data_page.forms[0]["form-0-algorithm"] = "3"
+ add_data_page.forms[0]["form-0-digest_type"] = "1"
+ add_data_page.forms[0]["form-0-digest"] = "GG1234"
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(
+ result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_CHARS)), count=2, status_code=200
+ )
+
+ def test_ds_data_form_invalid_digest_sha1(self):
+ """DS data form errors with invalid data (digest is invalid sha-1)
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-key_tag"] = "1234"
+ add_data_page.forms[0]["form-0-algorithm"] = "3"
+ add_data_page.forms[0]["form-0-digest_type"] = "1" # SHA-1
+ add_data_page.forms[0]["form-0-digest"] = "A123"
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(
+ result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA1)), count=2, status_code=200
+ )
+
+ def test_ds_data_form_invalid_digest_sha256(self):
+ """DS data form errors with invalid data (digest is invalid sha-256)
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}))
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-key_tag"] = "1234"
+ add_data_page.forms[0]["form-0-algorithm"] = "3"
+ add_data_page.forms[0]["form-0-digest_type"] = "2" # SHA-256
+ add_data_page.forms[0]["form-0-digest"] = "GG1234"
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(
+ result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA256)), count=2, status_code=200
+ )
diff --git a/src/registrar/views/__init__.py b/src/registrar/views/__init__.py
index c1400d7c0..8785c9076 100644
--- a/src/registrar/views/__init__.py
+++ b/src/registrar/views/__init__.py
@@ -12,6 +12,7 @@ from .domain import (
DomainUsersView,
DomainAddUserView,
DomainInvitationDeleteView,
+ DomainDeleteUserView,
)
from .health import *
from .index import *
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 4dce2301c..04fe1ce3a 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -34,6 +34,7 @@ from registrar.utility.errors import (
SecurityEmailErrorCodes,
)
from registrar.models.utility.contact_error import ContactError
+from registrar.views.utility.permission_views import UserDomainRolePermissionDeleteView
from ..forms import (
ContactForm,
@@ -632,6 +633,55 @@ class DomainUsersView(DomainBaseView):
template_name = "domain_users.html"
+ def get_context_data(self, **kwargs):
+ """The initial value for the form (which is a formset here)."""
+ context = super().get_context_data(**kwargs)
+
+ # Add conditionals to the context (such as "can_delete_users")
+ context = self._add_booleans_to_context(context)
+
+ # Add modal buttons to the context (such as for delete)
+ context = self._add_modal_buttons_to_context(context)
+
+ # Get the email of the current user
+ context["current_user_email"] = self.request.user.email
+
+ return context
+
+ def _add_booleans_to_context(self, context):
+ # Determine if the current user can delete managers
+ domain_pk = None
+ can_delete_users = False
+
+ if self.kwargs is not None and "pk" in self.kwargs:
+ domain_pk = self.kwargs["pk"]
+ # Prevent the end user from deleting themselves as a manager if they are the
+ # only manager that exists on a domain.
+ can_delete_users = UserDomainRole.objects.filter(domain__id=domain_pk).count() > 1
+
+ context["can_delete_users"] = can_delete_users
+ return context
+
+ def _add_modal_buttons_to_context(self, context):
+ """Adds modal buttons (and their HTML) to the context"""
+ # Create HTML for the modal button
+ modal_button = (
+ '
Yes, remove domain manager '
+ )
+ context["modal_button"] = modal_button
+
+ # Create HTML for the modal button when deleting yourself
+ modal_button_self = (
+ '
Yes, remove myself '
+ )
+ context["modal_button_self"] = modal_button_self
+
+ return context
+
class DomainAddUserView(DomainFormBaseView):
"""Inside of a domain's user management, a form for adding users.
@@ -745,3 +795,60 @@ class DomainInvitationDeleteView(DomainInvitationPermissionDeleteView, SuccessMe
def get_success_message(self, cleaned_data):
return f"Successfully canceled invitation for {self.object.email}."
+
+
+class DomainDeleteUserView(UserDomainRolePermissionDeleteView):
+ """Inside of a domain's user management, a form for deleting users."""
+
+ object: UserDomainRole # workaround for type mismatch in DeleteView
+
+ def get_object(self, queryset=None):
+ """Custom get_object definition to grab a UserDomainRole object from a domain_id and user_id"""
+ domain_id = self.kwargs.get("pk")
+ user_id = self.kwargs.get("user_pk")
+ return UserDomainRole.objects.get(domain=domain_id, user=user_id)
+
+ def get_success_url(self):
+ """Refreshes the page after a delete is successful"""
+ return reverse("domain-users", kwargs={"pk": self.object.domain.id})
+
+ def get_success_message(self, delete_self=False):
+ """Returns confirmation content for the deletion event"""
+
+ # Grab the text representation of the user we want to delete
+ email_or_name = self.object.user.email
+ if email_or_name is None or email_or_name.strip() == "":
+ email_or_name = self.object.user
+
+ # If the user is deleting themselves, return a specific message.
+ # If not, return something more generic.
+ if delete_self:
+ message = f"You are no longer managing the domain {self.object.domain}."
+ else:
+ message = f"Removed {email_or_name} as a manager for this domain."
+
+ return message
+
+ def form_valid(self, form):
+ """Delete the specified user on this domain."""
+
+ # Delete the object
+ super().form_valid(form)
+
+ # Is the user deleting themselves? If so, display a different message
+ delete_self = self.request.user == self.object.user
+
+ # Add a success message
+ messages.success(self.request, self.get_success_message(delete_self))
+ return redirect(self.get_success_url())
+
+ def post(self, request, *args, **kwargs):
+ """Custom post implementation to redirect to home in the event that the user deletes themselves"""
+ response = super().post(request, *args, **kwargs)
+
+ # If the user is deleting themselves, redirect to home
+ delete_self = self.request.user == self.object.user
+ if delete_self:
+ return redirect(reverse("home"))
+
+ return response
diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py
index 0cf5970df..b2c4cb364 100644
--- a/src/registrar/views/utility/mixins.py
+++ b/src/registrar/views/utility/mixins.py
@@ -286,6 +286,43 @@ class DomainApplicationPermission(PermissionsLoginMixin):
return True
+class UserDeleteDomainRolePermission(PermissionsLoginMixin):
+
+ """Permission mixin for UserDomainRole if user
+ has access, otherwise 403"""
+
+ def has_permission(self):
+ """Check if this user has access to this domain application.
+
+ The user is in self.request.user and the domain needs to be looked
+ up from the domain's primary key in self.kwargs["pk"]
+ """
+ domain_pk = self.kwargs["pk"]
+ user_pk = self.kwargs["user_pk"]
+
+ # Check if the user is authenticated
+ if not self.request.user.is_authenticated:
+ return False
+
+ # Check if the UserDomainRole object exists, then check
+ # if the user requesting the delete has permissions to do so
+ has_delete_permission = UserDomainRole.objects.filter(
+ user=user_pk,
+ domain=domain_pk,
+ domain__permissions__user=self.request.user,
+ ).exists()
+ if not has_delete_permission:
+ return False
+
+ # Check if more than one manager exists on the domain.
+ # If only one exists, prevent this from happening
+ has_multiple_managers = len(UserDomainRole.objects.filter(domain=domain_pk)) > 1
+ if not has_multiple_managers:
+ return False
+
+ return True
+
+
class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
"""Permission mixin that redirects to withdraw action on domain application
diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py
index 587eb0b5c..54c96d602 100644
--- a/src/registrar/views/utility/permission_views.py
+++ b/src/registrar/views/utility/permission_views.py
@@ -4,6 +4,7 @@ import abc # abstract base class
from django.views.generic import DetailView, DeleteView, TemplateView
from registrar.models import Domain, DomainApplication, DomainInvitation
+from registrar.models.user_domain_role import UserDomainRole
from .mixins import (
DomainPermission,
@@ -11,6 +12,7 @@ from .mixins import (
DomainApplicationPermissionWithdraw,
DomainInvitationPermission,
ApplicationWizardPermission,
+ UserDeleteDomainRolePermission,
)
import logging
@@ -130,3 +132,20 @@ class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteV
model = DomainApplication
object: DomainApplication
+
+
+class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC):
+
+ """Abstract base view for deleting a UserDomainRole.
+
+ This abstract view cannot be instantiated. Actual views must specify
+ `template_name`.
+ """
+
+ # DetailView property for what model this is viewing
+ model = UserDomainRole
+ # workaround for type mismatch in DeleteView
+ object: UserDomainRole
+
+ # variable name in template context for the model object
+ context_object_name = "userdomainrole"