unit tests and integration tests

Signed-off-by: CocoByte <nicolle.leclair@gmail.com>
This commit is contained in:
CocoByte 2023-10-27 11:22:47 -06:00
parent 15262f3747
commit 72ae138991
No known key found for this signature in database
GPG key ID: BBFAA2526384C97F
4 changed files with 229 additions and 105 deletions

View file

@ -9,7 +9,6 @@ from django.core.management import BaseCommand
from registrar.models import TransitionDomain
from registrar.management.commands.utility.terminal_helper import (
TerminalColors,
TerminalHelper,

View file

@ -15,6 +15,7 @@ from django.test import Client
from django_fsm import TransitionNotAllowed # type: ignore
from django.core.management import BaseCommand
from django.core.management import call_command
from registrar.models import (
Domain,
@ -98,7 +99,7 @@ class Command(BaseCommand):
)
parser.add_argument(
"--migrationFilenames",
default="escrow_domain_contacts.daily.gov.GOV.txt escrow_contacts.daily.gov.GOV.txt escrow_domain_statuses.daily.gov.GOV.txt",
default="escrow_domain_contacts.daily.gov.GOV.txt,escrow_contacts.daily.gov.GOV.txt,escrow_domain_statuses.daily.gov.GOV.txt",
help="""The files used for load_transition_domain migration script.
Must appear IN ORDER and separated by commas:
domain_contacts_filename.txt,contacts_filename.txt,domain_statuses_filename.txt
@ -225,12 +226,16 @@ class Command(BaseCommand):
debug_on: bool,
prompts_enabled: bool,
debug_max_entries_to_parse: int):
"""Runs the load_transition_domain script"""
# Create the command string
command_string = "./manage.py load_transition_domain "
command_string += file_location+domain_contacts_filename + " "
command_string += file_location+contacts_filename + " "
command_string += file_location+domain_statuses_filename + " "
command_script = "load_transition_domain"
command_string = (
f"./manage.py {command_script} "
f"{file_location+domain_contacts_filename} "
f"{file_location+contacts_filename} "
f"{file_location+domain_statuses_filename} "
)
if sep is not None and sep != "|":
command_string += f"--sep {sep} "
if reset_table:
@ -240,39 +245,59 @@ class Command(BaseCommand):
if debug_max_entries_to_parse > 0:
command_string += f"--limitParse {debug_max_entries_to_parse} "
# Execute the command string
if prompts_enabled:
system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate, command_string, "Running load_transition_domain script")
return
TerminalHelper.execute_command(command_string)
# TODO: make this somehow run inside TerminalHelper prompt
call_command(
command_script,
f"{file_location+domain_contacts_filename}",
f"{file_location+contacts_filename}",
f"{file_location+domain_statuses_filename}",
sep = sep,
resetTable = reset_table,
debug = debug_on,
limitParse = debug_max_entries_to_parse
)
def run_transfer_script(self, debug_on:bool, prompts_enabled: bool):
"""Runs the transfer_transition_domains_to_domains script"""
# Create the command string
command_string = "./manage.py transfer_transition_domains_to_domains "
command_script = "transfer_transition_domains_to_domains"
command_string = f"./manage.py {command_script}"
if debug_on:
command_string += "--debug "
# Execute the command string
if prompts_enabled:
system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate,command_string, "Running transfer_transition_domains_to_domains script")
return
TerminalHelper.execute_command(command_string)
# TODO: make this somehow run inside TerminalHelper prompt
call_command(
command_script
)
def run_send_invites_script(self, debug_on: bool, prompts_enabled: bool):
"""Runs the send_domain_invitations script"""
# Create the command string...
command_string = "./manage.py send_domain_invitations -s"
command_script = "send_domain_invitations"
command_string = f"./manage.py {command_script} -s"
# Execute the command string
if prompts_enabled:
system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate,command_string, "Running send_domain_invitations script")
return
TerminalHelper.execute_command(command_string)
# TODO: make this somehow run inside TerminalHelper prompt
call_command(
command_script,
s=True
)
def run_migration_scripts(self,
file_location,
@ -288,7 +313,6 @@ class Command(BaseCommand):
1 - imports for trans domains
2 - transfer to domain & domain invitation"""
if prompts_enabled:
# Allow the user to inspect the filepath
# data given in the arguments, and prompt
@ -342,12 +366,12 @@ class Command(BaseCommand):
"""Simulates logins for users (this will add
Domain Information objects to our tables)"""
logger.info(f""
f"{TerminalColors.OKCYAN}"
f"================== SIMULATING LOGINS =================="
f"{TerminalColors.ENDC}")
# logger.info(f""
# f"{TerminalColors.OKCYAN}"
# f"================== SIMULATING LOGINS =================="
# f"{TerminalColors.ENDC}")
# for invite in DomainInvitation.objects.all(): #TODO: limit to our stuff
# for invite in DomainInvitation.objects.all(): #TODO: move to unit test
# #DEBUG:
# TerminalHelper.print_conditional(debug_on,
# f"{TerminalColors.OKCYAN}"
@ -393,32 +417,8 @@ class Command(BaseCommand):
debug_on = options.get("debug")
prompts_enabled = options.get("prompt")
run_migrations_enabled = options.get("runMigrations")
# simulate_user_login_enabled = options.get("triggerLogins")
sep = options.get("sep")
reset_table = options.get("resetTable")
debug_max_entries_to_parse = int(
options.get("limitParse")
)
simulate_user_login_enabled = False # TODO: delete? Moving to unit test... options.get("triggerLogins")
# Grab filepath information from the arguments
file_location = options.get("migrationDirectory")+"/"
filenames = options.get("migrationFilenames").split(",")
if len(filenames) < 3:
filenames_as_string = "{}".format(", ".join(map(str, filenames)))
logger.info(f"""
{TerminalColors.FAIL}
--migrationFilenames expected 3 filenames to follow it,
but only {len(filenames)} were given:
{filenames_as_string}
PLEASE MODIFY THE SCRIPT AND TRY RUNNING IT AGAIN
============= TERMINATING =============
{TerminalColors.ENDC}
""")
sys.exit()
domain_contacts_filename = filenames[0]
contacts_filename = filenames[1]
domain_statuses_filename = filenames[2]
TerminalHelper.print_conditional(
debug_on,
@ -460,6 +460,34 @@ class Command(BaseCommand):
# STEP 1 -- RUN MIGRATIONS
# Run migration scripts if specified by user
if run_migrations_enabled:
# grab arguments for running migrations
sep = options.get("sep")
reset_table = options.get("resetTable")
debug_max_entries_to_parse = int(
options.get("limitParse")
)
# Grab filepath information from the arguments
file_location = options.get("migrationDirectory")+"/"
filenames = options.get("migrationFilenames").split(",")
if len(filenames) < 3:
filenames_as_string = "{}".format(", ".join(map(str, filenames)))
logger.info(f"""
{TerminalColors.FAIL}
--migrationFilenames expected 3 filenames to follow it,
but only {len(filenames)} were given:
{filenames_as_string}
PLEASE MODIFY THE SCRIPT AND TRY RUNNING IT AGAIN
============= TERMINATING =============
{TerminalColors.ENDC}
""")
sys.exit()
domain_contacts_filename = filenames[0]
contacts_filename = filenames[1]
domain_statuses_filename = filenames[2]
# Run migration scripts
self.run_migration_scripts(file_location,
domain_contacts_filename,
contacts_filename,
@ -482,24 +510,24 @@ class Command(BaseCommand):
# to ensure Domain Information objects get added
# to the database.)
# if run_migrations_enabled:
# if prompts_enabled:
# simulate_user_login_enabled = TerminalHelper.query_yes_no(
# f"""{TerminalColors.FAIL}
# Proceed with simulating user logins?
# {TerminalColors.ENDC}"""
# )
# if not simulate_user_login_enabled:
# return
# self.simulate_user_logins(debug_on)
# prompt_continuation_of_analysis = True
if run_migrations_enabled and simulate_user_login_enabled:
if prompts_enabled:
simulate_user_login_enabled = TerminalHelper.query_yes_no(
f"""{TerminalColors.FAIL}
Proceed with simulating user logins?
{TerminalColors.ENDC}"""
)
if not simulate_user_login_enabled:
return
self.simulate_user_logins(debug_on)
prompt_continuation_of_analysis = True
# STEP 3 -- SEND INVITES
proceed_with_sending_invites = run_migrations_enabled
if prompts_enabled and run_migrations_enabled:
proceed_with_sending_invites = TerminalHelper.query_yes_no(
f"""{TerminalColors.FAIL}
Proceed with sending user invites?
Proceed with sending user invites for all transition domains?
(Y = proceed, N = skip)
{TerminalColors.ENDC}"""
)

View file

@ -72,10 +72,14 @@ class TerminalHelper:
os.system(f"{command_string}")
def prompt_for_execution(system_exit_on_terminate: bool, command_string: str, prompt_title: str) -> bool:
"""Prompts the user to inspect the given terminal command string
and asks if they wish to execute it. If the user responds (y),
execute the command"""
def prompt_for_execution(system_exit_on_terminate: bool,
info_to_inspect: str,
prompt_title: str) -> bool:
"""Create to reduce code complexity.
Prompts the user to inspect the given string
and asks if they wish to execute it.
Returns true if the user responds (y),
Returns false if the user responds (n)"""
action_description_for_selecting_no = "skip"
if system_exit_on_terminate:
@ -88,21 +92,19 @@ class TerminalHelper:
=====================================================
{prompt_title}
=====================================================
*** IMPORTANT: VERIFY THE FOLLOWING COMMAND LOOKS CORRECT ***
*** IMPORTANT: VERIFY THE FOLLOWING LOOKS CORRECT ***
{command_string}
{info_to_inspect}
{TerminalColors.FAIL}
Proceed? (Y = proceed, N = {action_description_for_selecting_no})
{TerminalColors.ENDC}"""
)
# If the user decided to proceed executing the command,
# run the command for loading transition domains.
# Otherwise, exit this subroutine.
# If the user decided to proceed return true.
# Otherwise, either return false or exit this subroutine.
if not proceed_execution:
if system_exit_on_terminate:
sys.exit()
return False
TerminalHelper.execute_command(command_string)
return True

View file

@ -1,3 +1,4 @@
from unittest.mock import patch
from django.test import TestCase
from registrar.models import (
@ -10,21 +11,22 @@ from registrar.models import (
)
from registrar.management.commands.master_domain_migrations import Command as master_migration_command
from registrar.management.commands.utility.terminal_helper import (
TerminalHelper,
)
from django.core.management import call_command
class TestLogins(TestCase):
"""Test ......"""
""" """
def setUp(self):
""" """
# self.user, _ = User.objects.get_or_create(email=self.email)
# self.load_transition_domain_script = "load_transition_domain",
# self.transfer_script = "transfer_transition_domains_to_domains",
# self.master_script = "load_transition_domain",
# # clean out the roles each time
# UserDomainRole.objects.all().delete()
self.test_data_file_location = "/app/registrar/tests/data"
self.test_domain_contact_filename = "test_domain_contacts.txt"
self.test_contact_filename = "test_contacts.txt"
self.test_domain_status_filename = "test_domain_statuses.txt"
def tearDown(self):
super().tearDown()
@ -32,6 +34,29 @@ class TestLogins(TestCase):
Domain.objects.all().delete()
DomainInvitation.objects.all().delete()
DomainInformation.objects.all().delete()
User.objects.all().delete()
UserDomainRole.objects.all().delete()
def run_load_domains(self):
call_command(
"load_transition_domain",
f"{self.test_data_file_location}/{self.test_domain_contact_filename}",
f"{self.test_data_file_location}/{self.test_contact_filename}",
f"{self.test_data_file_location}/{self.test_domain_status_filename}",
)
def run_transfer_domains(self):
call_command("transfer_transition_domains_to_domains")
def run_master_script(self):
command = call_command(
"master_domain_migrations",
runMigrations=True,
migrationDirectory=f"{self.test_data_file_location}",
migrationFilenames=(f"{self.test_domain_contact_filename},"
f"{self.test_contact_filename},"
f"{self.test_domain_status_filename}"),
)
def compare_tables(self,
expected_total_transition_domains,
@ -103,6 +128,7 @@ class TestLogins(TestCase):
self.assertTrue(total_domain_informations == expected_total_domain_informations)
self.assertTrue(total_domain_invitations == expected_total_domain_invitations)
def test_master_migration_functions(self):
""" Run the full master migration script using local test data.
NOTE: This is more of an integration test and so far does not
@ -110,28 +136,23 @@ class TestLogins(TestCase):
But for now, this will double-check that the script
works as intended. """
migration_directory = "/app/registrar/tests/data/"
contacts_filename = "test_contacts.txt"
domain_contacts_filename = "test_domain_contacts.txt"
domain_statuses_filename = "test_domain_statuses.txt"
self.run_master_script()
# STEP 1: Run the master migration script using local test data
master_migration_command.run_load_transition_domain_script(master_migration_command(),
migration_directory,
domain_contacts_filename,
contacts_filename,
domain_statuses_filename,
"|",
False,
False,
False,
0)
# run_master_script_command = "./manage.py master_domain_migrations"
# run_master_script_command += " --runMigrations"
# run_master_script_command += " --migrationDirectory /app/registrar/tests/data"
# run_master_script_command += " --migrationFilenames test_contacts.txt,test_domain_contacts.txt,test_domain_statuses.txt"
# TerminalHelper.execute_command(run_master_script_command)
# TODO: instead of patching....there has got to be a way of making sure subsequent commands use the django database
# Patch subroutines for migrations
def side_effect():
self.run_load_domains()
self.run_transfer_domains()
patcher = patch("registrar.management.commands.master_domain_migrations.Command.run_migration_scripts")
mocked_get = patcher.start()
mocked_get.side_effect = side_effect
# Patch subroutines for sending invitations
def side_effect():
# TODO: what should happen here?
return
patcher = patch("registrar.management.commands.master_domain_migrations.Command.run_send_invites_script")
mocked_get = patcher.start()
mocked_get.side_effect = side_effect
# STEP 2: (analyze the tables just like the migration script does, but add assert statements)
expected_total_transition_domains = 8
@ -155,10 +176,84 @@ class TestLogins(TestCase):
expected_missing_domain_invitations,
)
def test_load_transition_domains():
""" """
def test_load_transition_domain(self):
def test_user_logins(self):
"""A new user's first_login callback retrieves their invitations."""
# self.user.first_login()
# self.assertTrue(UserDomainRole.objects.get(user=self.user, domain=self.domain))
self.run_load_domains()
# STEP 2: (analyze the tables just like the migration script does, but add assert statements)
expected_total_transition_domains = 8
expected_total_domains = 0
expected_total_domain_informations = 0
expected_total_domain_invitations = 0
expected_missing_domains = 8
expected_duplicate_domains = 0
expected_missing_domain_informations = 8
expected_missing_domain_invitations = 8
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_transfer_transition_domains_to_domains(self):
# TODO: setup manually instead of calling other script
self.run_load_domains()
self.run_transfer_domains()
# Analyze the tables
expected_total_transition_domains = 8
expected_total_domains = 4
expected_total_domain_informations = 0
expected_total_domain_invitations = 7
expected_missing_domains = 0
expected_duplicate_domains = 0
expected_missing_domain_informations = 8
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()
# 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.first_login()
# Analyze the tables
expected_total_transition_domains = 8
expected_total_domains = 4
expected_total_domain_informations = 3
expected_total_domain_invitations = 7
expected_missing_domains = 0
expected_duplicate_domains = 0
expected_missing_domain_informations = 1
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,
)