mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-16 09:37:03 +02:00
1048 lines
36 KiB
Python
1048 lines
36 KiB
Python
import datetime
|
|
import os
|
|
import logging
|
|
|
|
from contextlib import contextmanager
|
|
import random
|
|
from string import ascii_uppercase
|
|
from django.test import TestCase
|
|
from unittest.mock import MagicMock, Mock, patch
|
|
from typing import List, Dict
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth import get_user_model, login
|
|
|
|
from registrar.models import (
|
|
Contact,
|
|
DraftDomain,
|
|
Website,
|
|
DomainApplication,
|
|
DomainInvitation,
|
|
User,
|
|
UserGroup,
|
|
DomainInformation,
|
|
PublicContact,
|
|
Domain,
|
|
)
|
|
from epplibwrapper import (
|
|
commands,
|
|
common,
|
|
extensions,
|
|
info,
|
|
RegistryError,
|
|
ErrorCode,
|
|
responses,
|
|
)
|
|
|
|
from registrar.models.utility.contact_error import ContactError, ContactErrorCodes
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_handlers():
|
|
"""Obtain pointers to all StreamHandlers."""
|
|
handlers = {}
|
|
|
|
rootlogger = logging.getLogger()
|
|
for h in rootlogger.handlers:
|
|
if isinstance(h, logging.StreamHandler):
|
|
handlers[h.name] = h
|
|
|
|
for logger in logging.Logger.manager.loggerDict.values():
|
|
if not isinstance(logger, logging.PlaceHolder):
|
|
for h in logger.handlers:
|
|
if isinstance(h, logging.StreamHandler):
|
|
handlers[h.name] = h
|
|
|
|
return handlers
|
|
|
|
|
|
@contextmanager
|
|
def less_console_noise():
|
|
"""
|
|
Context manager to use in tests to silence console logging.
|
|
|
|
This is helpful on tests which trigger console messages
|
|
(such as errors) which are normal and expected.
|
|
|
|
It can easily be removed to debug a failing test.
|
|
"""
|
|
restore = {}
|
|
handlers = get_handlers()
|
|
devnull = open(os.devnull, "w")
|
|
|
|
# redirect all the streams
|
|
for handler in handlers.values():
|
|
prior = handler.setStream(devnull)
|
|
restore[handler.name] = prior
|
|
try:
|
|
# run the test
|
|
yield
|
|
finally:
|
|
# restore the streams
|
|
for handler in handlers.values():
|
|
handler.setStream(restore[handler.name])
|
|
# close the file we opened
|
|
devnull.close()
|
|
|
|
|
|
class MockUserLogin:
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
if request.user.is_anonymous:
|
|
user = None
|
|
UserModel = get_user_model()
|
|
username = "Testy"
|
|
args = {
|
|
UserModel.USERNAME_FIELD: username,
|
|
}
|
|
user, _ = UserModel.objects.get_or_create(**args)
|
|
user.is_staff = True
|
|
# Create or retrieve the group
|
|
group, _ = UserGroup.objects.get_or_create(name="full_access_group")
|
|
# Add the user to the group
|
|
user.groups.set([group])
|
|
user.save()
|
|
backend = settings.AUTHENTICATION_BACKENDS[-1]
|
|
login(request, user, backend=backend)
|
|
|
|
response = self.get_response(request)
|
|
return response
|
|
|
|
|
|
class MockSESClient(Mock):
|
|
EMAILS_SENT: List[Dict] = []
|
|
|
|
def send_email(self, *args, **kwargs):
|
|
self.EMAILS_SENT.append({"args": args, "kwargs": kwargs})
|
|
|
|
|
|
class AuditedAdminMockData:
|
|
"""Creates simple data mocks for AuditedAdminTest.
|
|
Can likely be more generalized, but the primary purpose of this class is to simplify
|
|
mock data creation, especially for lists of items,
|
|
by making the assumption that for most use cases we don't have to worry about
|
|
data 'accuracy' ('testy 2' is not an accurate first_name for example), we just care about
|
|
implementing some kind of patterning, especially with lists of items.
|
|
|
|
Two variables are used across multiple functions:
|
|
|
|
*item_name* - Used in patterning. Will be appended en masse to multiple str fields,
|
|
like first_name. For example, item_name 'egg' will return a user object of:
|
|
|
|
first_name: 'egg first_name:user',
|
|
last_name: 'egg last_name:user',
|
|
username: 'egg username:user'
|
|
|
|
where 'user' is the short_hand
|
|
|
|
*short_hand* - Used in patterning. Certain fields will have ':{shorthand}' appended to it,
|
|
as a way to optionally include metadata in the str itself. Can be further expanded on.
|
|
Came from a bug where different querysets used in testing would effectively be 'anonymized', wherein
|
|
it would only display a list of types, but not include the variable name.
|
|
""" # noqa
|
|
|
|
# Constants for different domain object types
|
|
INFORMATION = "information"
|
|
APPLICATION = "application"
|
|
INVITATION = "invitation"
|
|
|
|
def dummy_user(self, item_name, short_hand):
|
|
"""Creates a dummy user object,
|
|
but with a shorthand and support for multiple"""
|
|
user = User.objects.get_or_create(
|
|
first_name="{} first_name:{}".format(item_name, short_hand),
|
|
last_name="{} last_name:{}".format(item_name, short_hand),
|
|
username="{} username:{}".format(item_name, short_hand),
|
|
)[0]
|
|
return user
|
|
|
|
def dummy_contact(self, item_name, short_hand):
|
|
"""Creates a dummy contact object"""
|
|
contact = Contact.objects.get_or_create(
|
|
first_name="{} first_name:{}".format(item_name, short_hand),
|
|
last_name="{} last_name:{}".format(item_name, short_hand),
|
|
title="{} title:{}".format(item_name, short_hand),
|
|
email="{}testy@town.com".format(item_name),
|
|
phone="(555) 555 5555",
|
|
)[0]
|
|
return contact
|
|
|
|
def dummy_draft_domain(self, item_name, prebuilt=False):
|
|
"""
|
|
Creates a dummy DraftDomain object
|
|
Args:
|
|
item_name (str): Value for 'name' in a DraftDomain object.
|
|
prebuilt (boolean): Determines return type.
|
|
Returns:
|
|
DraftDomain: Where name = 'item_name'. If prebuilt = True, then
|
|
name will be "city{}.gov".format(item_name).
|
|
"""
|
|
if prebuilt:
|
|
item_name = "city{}.gov".format(item_name)
|
|
return DraftDomain.objects.get_or_create(name=item_name)[0]
|
|
|
|
def dummy_domain(self, item_name, prebuilt=False):
|
|
"""
|
|
Creates a dummy domain object
|
|
Args:
|
|
item_name (str): Value for 'name' in a Domain object.
|
|
prebuilt (boolean): Determines return type.
|
|
Returns:
|
|
Domain: Where name = 'item_name'. If prebuilt = True, then
|
|
domain name will be "city{}.gov".format(item_name).
|
|
"""
|
|
if prebuilt:
|
|
item_name = "city{}.gov".format(item_name)
|
|
return Domain.objects.get_or_create(name=item_name)[0]
|
|
|
|
def dummy_website(self, item_name):
|
|
"""
|
|
Creates a dummy website object
|
|
Args:
|
|
item_name (str): Value for 'website' in a Website object.
|
|
Returns:
|
|
Website: Where website = 'item_name'.
|
|
"""
|
|
return Website.objects.get_or_create(website=item_name)[0]
|
|
|
|
def dummy_alt(self, item_name):
|
|
"""
|
|
Creates a dummy website object for alternates
|
|
Args:
|
|
item_name (str): Value for 'website' in a Website object.
|
|
Returns:
|
|
Website: Where website = "cityalt{}.gov".format(item_name).
|
|
"""
|
|
return self.dummy_website(item_name="cityalt{}.gov".format(item_name))
|
|
|
|
def dummy_current(self, item_name):
|
|
"""
|
|
Creates a dummy website object for current
|
|
Args:
|
|
item_name (str): Value for 'website' in a Website object.
|
|
prebuilt (boolean): Determines return type.
|
|
Returns:
|
|
Website: Where website = "city{}.gov".format(item_name)
|
|
"""
|
|
return self.dummy_website(item_name="city{}.com".format(item_name))
|
|
|
|
def get_common_domain_arg_dictionary(
|
|
self,
|
|
item_name,
|
|
org_type="federal",
|
|
federal_type="executive",
|
|
purpose="Purpose of the site",
|
|
):
|
|
"""
|
|
Generates a generic argument dict for most domains
|
|
Args:
|
|
item_name (str): A shared str value appended to first_name, last_name,
|
|
organization_name, address_line1, address_line2,
|
|
title, email, and username.
|
|
|
|
org_type (str - optional): Sets a domains org_type
|
|
|
|
federal_type (str - optional): Sets a domains federal_type
|
|
|
|
purpose (str - optional): Sets a domains purpose
|
|
Returns:
|
|
Dictionary: {
|
|
organization_type: str,
|
|
federal_type: str,
|
|
purpose: str,
|
|
organization_name: str = "{} organization".format(item_name),
|
|
address_line1: str = "{} address_line1".format(item_name),
|
|
address_line2: str = "{} address_line2".format(item_name),
|
|
is_policy_acknowledged: boolean = True,
|
|
state_territory: str = "NY",
|
|
zipcode: str = "10002",
|
|
about_your_organization: str = "e-Government",
|
|
anything_else: str = "There is more",
|
|
authorizing_official: Contact = self.dummy_contact(item_name, "authorizing_official"),
|
|
submitter: Contact = self.dummy_contact(item_name, "submitter"),
|
|
creator: User = self.dummy_user(item_name, "creator"),
|
|
}
|
|
""" # noqa
|
|
common_args = dict(
|
|
organization_type=org_type,
|
|
federal_type=federal_type,
|
|
purpose=purpose,
|
|
organization_name="{} organization".format(item_name),
|
|
address_line1="{} address_line1".format(item_name),
|
|
address_line2="{} address_line2".format(item_name),
|
|
is_policy_acknowledged=True,
|
|
state_territory="NY",
|
|
zipcode="10002",
|
|
about_your_organization="e-Government",
|
|
anything_else="There is more",
|
|
authorizing_official=self.dummy_contact(item_name, "authorizing_official"),
|
|
submitter=self.dummy_contact(item_name, "submitter"),
|
|
creator=self.dummy_user(item_name, "creator"),
|
|
)
|
|
return common_args
|
|
|
|
def dummy_kwarg_boilerplate(
|
|
self,
|
|
domain_type,
|
|
item_name,
|
|
status=DomainApplication.STARTED,
|
|
org_type="federal",
|
|
federal_type="executive",
|
|
purpose="Purpose of the site",
|
|
):
|
|
"""
|
|
Returns a prebuilt kwarg dictionary for DomainApplication,
|
|
DomainInformation, or DomainInvitation.
|
|
Args:
|
|
domain_type (str): is either 'application', 'information',
|
|
or 'invitation'.
|
|
|
|
item_name (str): A shared str value appended to first_name, last_name,
|
|
organization_name, address_line1, address_line2,
|
|
title, email, and username.
|
|
|
|
status (str - optional): Defines the status for DomainApplication,
|
|
e.g. DomainApplication.STARTED
|
|
|
|
org_type (str - optional): Sets a domains org_type
|
|
|
|
federal_type (str - optional): Sets a domains federal_type
|
|
|
|
purpose (str - optional): Sets a domains purpose
|
|
Returns:
|
|
dict: Returns a dictionary structurally consistent with the expected input
|
|
of either DomainApplication, DomainInvitation, or DomainInformation
|
|
based on the 'domain_type' field.
|
|
""" # noqa
|
|
common_args = self.get_common_domain_arg_dictionary(
|
|
item_name, org_type, federal_type, purpose
|
|
)
|
|
full_arg_dict = None
|
|
match domain_type:
|
|
case self.APPLICATION:
|
|
full_arg_dict = dict(
|
|
**common_args,
|
|
requested_domain=self.dummy_draft_domain(item_name),
|
|
investigator=self.dummy_user(item_name, "investigator"),
|
|
status=status,
|
|
)
|
|
case self.INFORMATION:
|
|
domain_app = self.create_full_dummy_domain_application(item_name)
|
|
full_arg_dict = dict(
|
|
**common_args,
|
|
domain=self.dummy_domain(item_name, True),
|
|
domain_application=domain_app,
|
|
)
|
|
case self.INVITATION:
|
|
full_arg_dict = dict(
|
|
email="test_mail@mail.com",
|
|
domain=self.dummy_domain(item_name, True),
|
|
status=DomainInvitation.INVITED,
|
|
)
|
|
return full_arg_dict
|
|
|
|
def create_full_dummy_domain_application(
|
|
self, item_name, status=DomainApplication.STARTED
|
|
):
|
|
"""Creates a dummy domain application object"""
|
|
domain_application_kwargs = self.dummy_kwarg_boilerplate(
|
|
self.APPLICATION, item_name, status
|
|
)
|
|
application = DomainApplication.objects.get_or_create(
|
|
**domain_application_kwargs
|
|
)[0]
|
|
return application
|
|
|
|
def create_full_dummy_domain_information(
|
|
self, item_name, status=DomainApplication.STARTED
|
|
):
|
|
"""Creates a dummy domain information object"""
|
|
domain_application_kwargs = self.dummy_kwarg_boilerplate(
|
|
self.INFORMATION, item_name, status
|
|
)
|
|
application = DomainInformation.objects.get_or_create(
|
|
**domain_application_kwargs
|
|
)[0]
|
|
return application
|
|
|
|
def create_full_dummy_domain_invitation(
|
|
self, item_name, status=DomainApplication.STARTED
|
|
):
|
|
"""Creates a dummy domain invitation object"""
|
|
domain_application_kwargs = self.dummy_kwarg_boilerplate(
|
|
self.INVITATION, item_name, status
|
|
)
|
|
application = DomainInvitation.objects.get_or_create(
|
|
**domain_application_kwargs
|
|
)[0]
|
|
|
|
return application
|
|
|
|
def create_full_dummy_domain_object(
|
|
self,
|
|
domain_type,
|
|
item_name,
|
|
has_other_contacts=True,
|
|
has_current_website=True,
|
|
has_alternative_gov_domain=True,
|
|
status=DomainApplication.STARTED,
|
|
):
|
|
"""A helper to create a dummy domain application object"""
|
|
application = None
|
|
match domain_type:
|
|
case self.APPLICATION:
|
|
application = self.create_full_dummy_domain_application(
|
|
item_name, status
|
|
)
|
|
case self.INVITATION:
|
|
application = self.create_full_dummy_domain_invitation(
|
|
item_name, status
|
|
)
|
|
case self.INFORMATION:
|
|
application = self.create_full_dummy_domain_information(
|
|
item_name, status
|
|
)
|
|
case _:
|
|
raise ValueError("Invalid domain_type, must conform to given constants")
|
|
|
|
if has_other_contacts and domain_type != self.INVITATION:
|
|
other = self.dummy_contact(item_name, "other")
|
|
application.other_contacts.add(other)
|
|
if has_current_website and domain_type == self.APPLICATION:
|
|
current = self.dummy_current(item_name)
|
|
application.current_websites.add(current)
|
|
if has_alternative_gov_domain and domain_type == self.APPLICATION:
|
|
alt = self.dummy_alt(item_name)
|
|
application.alternative_domains.add(alt)
|
|
|
|
return application
|
|
|
|
|
|
def mock_user():
|
|
"""A simple user."""
|
|
user_kwargs = dict(
|
|
id=4,
|
|
first_name="Rachid",
|
|
last_name="Mrad",
|
|
)
|
|
mock_user, _ = User.objects.get_or_create(**user_kwargs)
|
|
return mock_user
|
|
|
|
|
|
def create_superuser():
|
|
User = get_user_model()
|
|
p = "adminpass"
|
|
user = User.objects.create_user(
|
|
username="superuser",
|
|
email="admin@example.com",
|
|
is_staff=True,
|
|
password=p,
|
|
)
|
|
# Retrieve the group or create it if it doesn't exist
|
|
group, _ = UserGroup.objects.get_or_create(name="full_access_group")
|
|
# Add the user to the group
|
|
user.groups.set([group])
|
|
return user
|
|
|
|
|
|
def create_user():
|
|
User = get_user_model()
|
|
p = "userpass"
|
|
user = User.objects.create_user(
|
|
username="staffuser",
|
|
email="user@example.com",
|
|
is_staff=True,
|
|
password=p,
|
|
)
|
|
# Retrieve the group or create it if it doesn't exist
|
|
group, _ = UserGroup.objects.get_or_create(name="cisa_analysts_group")
|
|
# Add the user to the group
|
|
user.groups.set([group])
|
|
return user
|
|
|
|
|
|
def create_ready_domain():
|
|
domain, _ = Domain.objects.get_or_create(name="city.gov", state=Domain.State.READY)
|
|
return domain
|
|
|
|
|
|
def completed_application(
|
|
has_other_contacts=True,
|
|
has_current_website=True,
|
|
has_alternative_gov_domain=True,
|
|
has_about_your_organization=True,
|
|
has_anything_else=True,
|
|
status=DomainApplication.STARTED,
|
|
user=False,
|
|
name="city.gov",
|
|
):
|
|
"""A completed domain application."""
|
|
if not user:
|
|
user = get_user_model().objects.create(username="username")
|
|
ao, _ = Contact.objects.get_or_create(
|
|
first_name="Testy",
|
|
last_name="Tester",
|
|
title="Chief Tester",
|
|
email="testy@town.com",
|
|
phone="(555) 555 5555",
|
|
)
|
|
domain, _ = DraftDomain.objects.get_or_create(name=name)
|
|
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="Testy2",
|
|
last_name="Tester2",
|
|
title="Admin Tester",
|
|
email="mayor@igorville.gov",
|
|
phone="(555) 555 5556",
|
|
)
|
|
other, _ = Contact.objects.get_or_create(
|
|
first_name="Testy",
|
|
last_name="Tester",
|
|
title="Another Tester",
|
|
email="testy2@town.com",
|
|
phone="(555) 555 5557",
|
|
)
|
|
domain_application_kwargs = dict(
|
|
organization_type="federal",
|
|
federal_type="executive",
|
|
purpose="Purpose of the site",
|
|
is_policy_acknowledged=True,
|
|
organization_name="Testorg",
|
|
address_line1="address 1",
|
|
address_line2="address 2",
|
|
state_territory="NY",
|
|
zipcode="10002",
|
|
authorizing_official=ao,
|
|
requested_domain=domain,
|
|
submitter=you,
|
|
creator=user,
|
|
status=status,
|
|
)
|
|
if has_about_your_organization:
|
|
domain_application_kwargs["about_your_organization"] = "e-Government"
|
|
if has_anything_else:
|
|
domain_application_kwargs["anything_else"] = "There is more"
|
|
|
|
application, _ = DomainApplication.objects.get_or_create(
|
|
**domain_application_kwargs
|
|
)
|
|
|
|
if has_other_contacts:
|
|
application.other_contacts.add(other)
|
|
if has_current_website:
|
|
application.current_websites.add(current)
|
|
if has_alternative_gov_domain:
|
|
application.alternative_domains.add(alt)
|
|
|
|
return application
|
|
|
|
|
|
def multiple_unalphabetical_domain_objects(
|
|
domain_type=AuditedAdminMockData.APPLICATION,
|
|
):
|
|
"""Returns a list of generic domain objects for testing purposes"""
|
|
applications = []
|
|
list_of_letters = list(ascii_uppercase)
|
|
random.shuffle(list_of_letters)
|
|
|
|
mock = AuditedAdminMockData()
|
|
for object_name in list_of_letters:
|
|
application = mock.create_full_dummy_domain_object(domain_type, object_name)
|
|
applications.append(application)
|
|
return applications
|
|
|
|
|
|
def generic_domain_object(domain_type, object_name):
|
|
"""Returns a generic domain object of
|
|
domain_type 'application', 'information', or 'invitation'"""
|
|
mock = AuditedAdminMockData()
|
|
application = mock.create_full_dummy_domain_object(domain_type, object_name)
|
|
return application
|
|
|
|
|
|
class MockEppLib(TestCase):
|
|
class fakedEppObject(object):
|
|
""""""
|
|
|
|
def __init__(
|
|
self,
|
|
auth_info=...,
|
|
cr_date=...,
|
|
contacts=...,
|
|
hosts=...,
|
|
statuses=...,
|
|
avail=...,
|
|
addrs=...,
|
|
registrant=...,
|
|
):
|
|
self.auth_info = auth_info
|
|
self.cr_date = cr_date
|
|
self.contacts = contacts
|
|
self.hosts = hosts
|
|
self.statuses = statuses
|
|
self.avail = avail # use for CheckDomain
|
|
self.addrs = addrs
|
|
self.registrant = registrant
|
|
|
|
def dummyInfoContactResultData(
|
|
self,
|
|
id,
|
|
email,
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
pw="thisisnotapassword",
|
|
):
|
|
fake = info.InfoContactResultData(
|
|
id=id,
|
|
postal_info=common.PostalInfo(
|
|
name="Registry Customer Service",
|
|
addr=common.ContactAddr(
|
|
street=["4200 Wilson Blvd."],
|
|
city="Arlington",
|
|
pc="22201",
|
|
cc="US",
|
|
sp="VA",
|
|
),
|
|
org="Cybersecurity and Infrastructure Security Agency",
|
|
type="type",
|
|
),
|
|
voice="+1.8882820870",
|
|
fax="+1-212-9876543",
|
|
email=email,
|
|
auth_info=common.ContactAuthInfo(pw=pw),
|
|
roid=...,
|
|
statuses=[],
|
|
cl_id=...,
|
|
cr_id=...,
|
|
cr_date=cr_date,
|
|
up_id=...,
|
|
up_date=...,
|
|
tr_date=...,
|
|
disclose=...,
|
|
vat=...,
|
|
ident=...,
|
|
notify_email=...,
|
|
)
|
|
return fake
|
|
|
|
mockDataInfoDomain = fakedEppObject(
|
|
"fakePw",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[
|
|
common.DomainContact(
|
|
contact="123", type=PublicContact.ContactTypeChoices.SECURITY
|
|
)
|
|
],
|
|
hosts=["fake.host.com"],
|
|
statuses=[
|
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
|
common.Status(state="inactive", description="", lang="en"),
|
|
],
|
|
)
|
|
mockDataInfoContact = mockDataInfoDomain.dummyInfoContactResultData(
|
|
"123", "123@mail.gov", datetime.datetime(2023, 5, 25, 19, 45, 35), "lastPw"
|
|
)
|
|
InfoDomainWithContacts = fakedEppObject(
|
|
"fakepw",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[
|
|
common.DomainContact(
|
|
contact="securityContact",
|
|
type=PublicContact.ContactTypeChoices.SECURITY,
|
|
),
|
|
common.DomainContact(
|
|
contact="technicalContact",
|
|
type=PublicContact.ContactTypeChoices.TECHNICAL,
|
|
),
|
|
common.DomainContact(
|
|
contact="adminContact",
|
|
type=PublicContact.ContactTypeChoices.ADMINISTRATIVE,
|
|
),
|
|
],
|
|
hosts=["fake.host.com"],
|
|
statuses=[
|
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
|
common.Status(state="inactive", description="", lang="en"),
|
|
],
|
|
registrant="regContact",
|
|
)
|
|
|
|
InfoDomainWithDefaultSecurityContact = fakedEppObject(
|
|
"fakepw",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[
|
|
common.DomainContact(
|
|
contact="defaultSec",
|
|
type=PublicContact.ContactTypeChoices.SECURITY,
|
|
)
|
|
],
|
|
hosts=["fake.host.com"],
|
|
statuses=[
|
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
|
common.Status(state="inactive", description="", lang="en"),
|
|
],
|
|
)
|
|
|
|
InfoDomainWithDefaultTechnicalContact = fakedEppObject(
|
|
"fakepw",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[
|
|
common.DomainContact(
|
|
contact="defaultTech",
|
|
type=PublicContact.ContactTypeChoices.TECHNICAL,
|
|
)
|
|
],
|
|
hosts=["fake.host.com"],
|
|
statuses=[
|
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
|
common.Status(state="inactive", description="", lang="en"),
|
|
],
|
|
)
|
|
|
|
mockDefaultTechnicalContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"defaultTech", "dotgov@cisa.dhs.gov"
|
|
)
|
|
mockDefaultSecurityContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"defaultSec", "dotgov@cisa.dhs.gov"
|
|
)
|
|
mockSecurityContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"securityContact", "security@mail.gov"
|
|
)
|
|
mockTechnicalContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"technicalContact", "tech@mail.gov"
|
|
)
|
|
mockAdministrativeContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"adminContact", "admin@mail.gov"
|
|
)
|
|
mockRegistrantContact = InfoDomainWithContacts.dummyInfoContactResultData(
|
|
"regContact", "registrant@mail.gov"
|
|
)
|
|
|
|
infoDomainNoContact = fakedEppObject(
|
|
"security",
|
|
cr_date=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),
|
|
contacts=[],
|
|
hosts=[
|
|
"ns1.my-nameserver-1.com",
|
|
"ns1.my-nameserver-2.com",
|
|
"ns1.cats-are-superior3.com",
|
|
],
|
|
)
|
|
infoDomainNoHost = fakedEppObject(
|
|
"my-nameserver.gov",
|
|
cr_date=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),
|
|
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),
|
|
addrs=["1.2.3.4", "2.3.4.5"],
|
|
)
|
|
|
|
mockDataHostChange = fakedEppObject(
|
|
"lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35)
|
|
)
|
|
addDsData1 = {
|
|
"keyTag": 1234,
|
|
"alg": 3,
|
|
"digestType": 1,
|
|
"digest": "ec0bdd990b39feead889f0ba613db4adec0bdd99",
|
|
}
|
|
addDsData2 = {
|
|
"keyTag": 2345,
|
|
"alg": 3,
|
|
"digestType": 1,
|
|
"digest": "ec0bdd990b39feead889f0ba613db4adecb4adec",
|
|
}
|
|
keyDataDict = {
|
|
"flags": 257,
|
|
"protocol": 3,
|
|
"alg": 1,
|
|
"pubKey": "AQPJ////4Q==",
|
|
}
|
|
dnssecExtensionWithDsData = extensions.DNSSECExtension(
|
|
**{
|
|
"dsData": [
|
|
common.DSData(**addDsData1) # type: ignore
|
|
], # type: ignore
|
|
}
|
|
)
|
|
dnssecExtensionWithMultDsData = extensions.DNSSECExtension(
|
|
**{
|
|
"dsData": [
|
|
common.DSData(**addDsData1), # type: ignore
|
|
common.DSData(**addDsData2), # type: ignore
|
|
], # type: ignore
|
|
}
|
|
)
|
|
dnssecExtensionWithKeyData = extensions.DNSSECExtension(
|
|
**{
|
|
"keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
|
|
}
|
|
)
|
|
dnssecExtensionRemovingDsData = extensions.DNSSECExtension()
|
|
|
|
infoDomainHasIP = fakedEppObject(
|
|
"nameserverwithip.gov",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[],
|
|
hosts=[
|
|
"ns1.nameserverwithip.gov",
|
|
"ns2.nameserverwithip.gov",
|
|
"ns3.nameserverwithip.gov",
|
|
],
|
|
addrs=["1.2.3.4", "2.3.4.5"],
|
|
)
|
|
|
|
infoDomainCheckHostIPCombo = fakedEppObject(
|
|
"nameserversubdomain.gov",
|
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
|
contacts=[],
|
|
hosts=[
|
|
"ns1.nameserversubdomain.gov",
|
|
"ns2.nameserversubdomain.gov",
|
|
],
|
|
)
|
|
|
|
def _mockDomainName(self, _name, _avail=False):
|
|
return MagicMock(
|
|
res_data=[
|
|
responses.check.CheckDomainResultData(
|
|
name=_name, avail=_avail, reason=None
|
|
),
|
|
]
|
|
)
|
|
|
|
def mockCheckDomainCommand(self, _request, cleaned):
|
|
if "gsa.gov" in getattr(_request, "names", None):
|
|
return self._mockDomainName("gsa.gov", True)
|
|
elif "GSA.gov" in getattr(_request, "names", None):
|
|
return self._mockDomainName("GSA.gov", True)
|
|
elif "igorvilleremixed.gov" in getattr(_request, "names", None):
|
|
return self._mockDomainName("igorvilleremixed.gov", False)
|
|
elif "errordomain.gov" in getattr(_request, "names", None):
|
|
raise RegistryError("Registry cannot find domain availability.")
|
|
else:
|
|
return self._mockDomainName("domainnotfound.gov", False)
|
|
|
|
def mockSend(self, _request, cleaned):
|
|
"""Mocks the registry.send function used inside of domain.py
|
|
registry is imported from epplibwrapper
|
|
returns objects that simulate what would be in a epp response
|
|
but only relevant pieces for tests"""
|
|
|
|
match type(_request):
|
|
case commands.InfoDomain:
|
|
return self.mockInfoDomainCommands(_request, cleaned)
|
|
case commands.InfoContact:
|
|
return self.mockInfoContactCommands(_request, cleaned)
|
|
case commands.CreateContact:
|
|
return self.mockCreateContactCommands(_request, cleaned)
|
|
case commands.UpdateDomain:
|
|
return self.mockUpdateDomainCommands(_request, cleaned)
|
|
case commands.CreateHost:
|
|
return MagicMock(
|
|
res_data=[self.mockDataHostChange],
|
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
|
)
|
|
case commands.UpdateHost:
|
|
return MagicMock(
|
|
res_data=[self.mockDataHostChange],
|
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
|
)
|
|
case commands.DeleteHost:
|
|
return MagicMock(
|
|
res_data=[self.mockDataHostChange],
|
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
|
)
|
|
case commands.CheckDomain:
|
|
return self.mockCheckDomainCommand(_request, cleaned)
|
|
case commands.DeleteDomain:
|
|
return self.mockDeleteDomainCommands(_request, cleaned)
|
|
case _:
|
|
return MagicMock(res_data=[self.mockDataInfoHosts])
|
|
|
|
def mockUpdateDomainCommands(self, _request, cleaned):
|
|
if getattr(_request, "name", None) == "dnssec-invalid.gov":
|
|
raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
|
|
else:
|
|
return MagicMock(
|
|
res_data=[self.mockDataHostChange],
|
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
|
)
|
|
|
|
def mockDeleteDomainCommands(self, _request, cleaned):
|
|
if getattr(_request, "name", None) == "failDelete.gov":
|
|
name = getattr(_request, "name", None)
|
|
fake_nameserver = "ns1.failDelete.gov"
|
|
if name in fake_nameserver:
|
|
raise RegistryError(
|
|
code=ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION
|
|
)
|
|
return None
|
|
|
|
def mockInfoDomainCommands(self, _request, cleaned):
|
|
request_name = getattr(_request, "name", None)
|
|
|
|
# Define a dictionary to map request names to data and extension values
|
|
request_mappings = {
|
|
"security.gov": (self.infoDomainNoContact, None),
|
|
"dnssec-dsdata.gov": (
|
|
self.mockDataInfoDomain,
|
|
self.dnssecExtensionWithDsData,
|
|
),
|
|
"dnssec-multdsdata.gov": (
|
|
self.mockDataInfoDomain,
|
|
self.dnssecExtensionWithMultDsData,
|
|
),
|
|
"dnssec-keydata.gov": (
|
|
self.mockDataInfoDomain,
|
|
self.dnssecExtensionWithKeyData,
|
|
),
|
|
"dnssec-none.gov": (self.mockDataInfoDomain, None),
|
|
"my-nameserver.gov": (
|
|
self.infoDomainTwoHosts
|
|
if self.mockedSendFunction.call_count == 5
|
|
else self.infoDomainNoHost,
|
|
None,
|
|
),
|
|
"nameserverwithip.gov": (self.infoDomainHasIP, None),
|
|
"namerserversubdomain.gov": (self.infoDomainCheckHostIPCombo, None),
|
|
"freeman.gov": (self.InfoDomainWithContacts, None),
|
|
"threenameserversDomain.gov": (self.infoDomainThreeHosts, None),
|
|
"defaultsecurity.gov": (self.InfoDomainWithDefaultSecurityContact, None),
|
|
"defaulttechnical.gov": (self.InfoDomainWithDefaultTechnicalContact, None),
|
|
}
|
|
|
|
# Retrieve the corresponding values from the dictionary
|
|
res_data, extensions = request_mappings.get(
|
|
request_name, (self.mockDataInfoDomain, None)
|
|
)
|
|
|
|
return MagicMock(
|
|
res_data=[res_data],
|
|
extensions=[extensions] if extensions is not None else [],
|
|
)
|
|
|
|
def mockInfoContactCommands(self, _request, cleaned):
|
|
mocked_result: info.InfoContactResultData
|
|
|
|
# For testing contact types
|
|
match getattr(_request, "id", None):
|
|
case "securityContact":
|
|
mocked_result = self.mockSecurityContact
|
|
case "technicalContact":
|
|
mocked_result = self.mockTechnicalContact
|
|
case "adminContact":
|
|
mocked_result = self.mockAdministrativeContact
|
|
case "regContact":
|
|
mocked_result = self.mockRegistrantContact
|
|
case "defaultSec":
|
|
mocked_result = self.mockDefaultSecurityContact
|
|
case "defaultTech":
|
|
mocked_result = self.mockDefaultTechnicalContact
|
|
case _:
|
|
# Default contact return
|
|
mocked_result = self.mockDataInfoContact
|
|
|
|
return MagicMock(res_data=[mocked_result])
|
|
|
|
def mockCreateContactCommands(self, _request, cleaned):
|
|
if (
|
|
getattr(_request, "id", None) == "fail"
|
|
and self.mockedSendFunction.call_count == 3
|
|
):
|
|
# use this for when a contact is being updated
|
|
# sets the second send() to fail
|
|
raise RegistryError(code=ErrorCode.OBJECT_EXISTS)
|
|
elif getattr(_request, "email", None) == "test@failCreate.gov":
|
|
# use this for when a contact is being updated
|
|
# mocks a registry error on creation
|
|
raise RegistryError(code=None)
|
|
elif getattr(_request, "email", None) == "test@contactError.gov":
|
|
# use this for when a contact is being updated
|
|
# mocks a contact error on creation
|
|
raise ContactError(code=ContactErrorCodes.CONTACT_TYPE_NONE)
|
|
return MagicMock(res_data=[self.mockDataInfoHosts])
|
|
|
|
def setUp(self):
|
|
"""mock epp send function as this will fail locally"""
|
|
self.mockSendPatch = patch("registrar.models.domain.registry.send")
|
|
self.mockedSendFunction = self.mockSendPatch.start()
|
|
self.mockedSendFunction.side_effect = self.mockSend
|
|
|
|
def _convertPublicContactToEpp(
|
|
self, contact: PublicContact, disclose_email=False, createContact=True
|
|
):
|
|
DF = common.DiscloseField
|
|
fields = {DF.EMAIL}
|
|
|
|
di = common.Disclose(
|
|
flag=disclose_email,
|
|
fields=fields,
|
|
)
|
|
|
|
# check docs here looks like we may have more than one address field but
|
|
addr = common.ContactAddr(
|
|
[
|
|
getattr(contact, street)
|
|
for street in ["street1", "street2", "street3"]
|
|
if hasattr(contact, street)
|
|
], # type: ignore
|
|
city=contact.city,
|
|
pc=contact.pc,
|
|
cc=contact.cc,
|
|
sp=contact.sp,
|
|
) # type: ignore
|
|
|
|
pi = common.PostalInfo(
|
|
name=contact.name,
|
|
addr=addr,
|
|
org=contact.org,
|
|
type="loc",
|
|
)
|
|
|
|
ai = common.ContactAuthInfo(pw="2fooBAR123fooBaz")
|
|
if createContact:
|
|
return commands.CreateContact(
|
|
id=contact.registry_id,
|
|
postal_info=pi, # type: ignore
|
|
email=contact.email,
|
|
voice=contact.voice,
|
|
fax=contact.fax,
|
|
auth_info=ai,
|
|
disclose=di,
|
|
vat=None,
|
|
ident=None,
|
|
notify_email=None,
|
|
) # type: ignore
|
|
else:
|
|
return commands.UpdateContact(
|
|
id=contact.registry_id,
|
|
postal_info=pi,
|
|
email=contact.email,
|
|
voice=contact.voice,
|
|
fax=contact.fax,
|
|
)
|
|
|
|
def tearDown(self):
|
|
self.mockSendPatch.stop()
|