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.models import TransitionDomain
from registrar.management.commands.utility.terminal_helper import ( from registrar.management.commands.utility.terminal_helper import (
TerminalColors, TerminalColors,
TerminalHelper, TerminalHelper,

View file

@ -15,6 +15,7 @@ from django.test import Client
from django_fsm import TransitionNotAllowed # type: ignore from django_fsm import TransitionNotAllowed # type: ignore
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.core.management import call_command
from registrar.models import ( from registrar.models import (
Domain, Domain,
@ -98,7 +99,7 @@ class Command(BaseCommand):
) )
parser.add_argument( parser.add_argument(
"--migrationFilenames", "--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. help="""The files used for load_transition_domain migration script.
Must appear IN ORDER and separated by commas: Must appear IN ORDER and separated by commas:
domain_contacts_filename.txt,contacts_filename.txt,domain_statuses_filename.txt domain_contacts_filename.txt,contacts_filename.txt,domain_statuses_filename.txt
@ -225,12 +226,16 @@ class Command(BaseCommand):
debug_on: bool, debug_on: bool,
prompts_enabled: bool, prompts_enabled: bool,
debug_max_entries_to_parse: int): debug_max_entries_to_parse: int):
"""Runs the load_transition_domain script""" """Runs the load_transition_domain script"""
# Create the command string # Create the command string
command_string = "./manage.py load_transition_domain " command_script = "load_transition_domain"
command_string += file_location+domain_contacts_filename + " " command_string = (
command_string += file_location+contacts_filename + " " f"./manage.py {command_script} "
command_string += file_location+domain_statuses_filename + " " f"{file_location+domain_contacts_filename} "
f"{file_location+contacts_filename} "
f"{file_location+domain_statuses_filename} "
)
if sep is not None and sep != "|": if sep is not None and sep != "|":
command_string += f"--sep {sep} " command_string += f"--sep {sep} "
if reset_table: if reset_table:
@ -240,39 +245,59 @@ class Command(BaseCommand):
if debug_max_entries_to_parse > 0: if debug_max_entries_to_parse > 0:
command_string += f"--limitParse {debug_max_entries_to_parse} " command_string += f"--limitParse {debug_max_entries_to_parse} "
# Execute the command string # Execute the command string
if prompts_enabled: if prompts_enabled:
system_exit_on_terminate = True system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate, command_string, "Running load_transition_domain script") 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): def run_transfer_script(self, debug_on:bool, prompts_enabled: bool):
"""Runs the transfer_transition_domains_to_domains script""" """Runs the transfer_transition_domains_to_domains script"""
# Create the command string # 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: if debug_on:
command_string += "--debug " command_string += "--debug "
# Execute the command string # Execute the command string
if prompts_enabled: if prompts_enabled:
system_exit_on_terminate = True system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate,command_string, "Running transfer_transition_domains_to_domains script") 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): def run_send_invites_script(self, debug_on: bool, prompts_enabled: bool):
"""Runs the send_domain_invitations script""" """Runs the send_domain_invitations script"""
# Create the command string... # 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 # Execute the command string
if prompts_enabled: if prompts_enabled:
system_exit_on_terminate = True system_exit_on_terminate = True
TerminalHelper.prompt_for_execution(system_exit_on_terminate,command_string, "Running send_domain_invitations script") 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, def run_migration_scripts(self,
file_location, file_location,
@ -288,7 +313,6 @@ class Command(BaseCommand):
1 - imports for trans domains 1 - imports for trans domains
2 - transfer to domain & domain invitation""" 2 - transfer to domain & domain invitation"""
if prompts_enabled: if prompts_enabled:
# Allow the user to inspect the filepath # Allow the user to inspect the filepath
# data given in the arguments, and prompt # data given in the arguments, and prompt
@ -342,12 +366,12 @@ class Command(BaseCommand):
"""Simulates logins for users (this will add """Simulates logins for users (this will add
Domain Information objects to our tables)""" Domain Information objects to our tables)"""
logger.info(f"" # logger.info(f""
f"{TerminalColors.OKCYAN}" # f"{TerminalColors.OKCYAN}"
f"================== SIMULATING LOGINS ==================" # f"================== SIMULATING LOGINS =================="
f"{TerminalColors.ENDC}") # 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: # #DEBUG:
# TerminalHelper.print_conditional(debug_on, # TerminalHelper.print_conditional(debug_on,
# f"{TerminalColors.OKCYAN}" # f"{TerminalColors.OKCYAN}"
@ -393,32 +417,8 @@ class Command(BaseCommand):
debug_on = options.get("debug") debug_on = options.get("debug")
prompts_enabled = options.get("prompt") prompts_enabled = options.get("prompt")
run_migrations_enabled = options.get("runMigrations") run_migrations_enabled = options.get("runMigrations")
# simulate_user_login_enabled = options.get("triggerLogins") simulate_user_login_enabled = False # TODO: delete? Moving to unit test... options.get("triggerLogins")
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]
TerminalHelper.print_conditional( TerminalHelper.print_conditional(
debug_on, debug_on,
@ -460,6 +460,34 @@ class Command(BaseCommand):
# STEP 1 -- RUN MIGRATIONS # STEP 1 -- RUN MIGRATIONS
# Run migration scripts if specified by user # Run migration scripts if specified by user
if run_migrations_enabled: 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, self.run_migration_scripts(file_location,
domain_contacts_filename, domain_contacts_filename,
contacts_filename, contacts_filename,
@ -482,24 +510,24 @@ class Command(BaseCommand):
# to ensure Domain Information objects get added # to ensure Domain Information objects get added
# to the database.) # to the database.)
# if run_migrations_enabled: if run_migrations_enabled and simulate_user_login_enabled:
# if prompts_enabled: if prompts_enabled:
# simulate_user_login_enabled = TerminalHelper.query_yes_no( simulate_user_login_enabled = TerminalHelper.query_yes_no(
# f"""{TerminalColors.FAIL} f"""{TerminalColors.FAIL}
# Proceed with simulating user logins? Proceed with simulating user logins?
# {TerminalColors.ENDC}""" {TerminalColors.ENDC}"""
# ) )
# if not simulate_user_login_enabled: if not simulate_user_login_enabled:
# return return
# self.simulate_user_logins(debug_on) self.simulate_user_logins(debug_on)
# prompt_continuation_of_analysis = True prompt_continuation_of_analysis = True
# STEP 3 -- SEND INVITES # STEP 3 -- SEND INVITES
proceed_with_sending_invites = run_migrations_enabled proceed_with_sending_invites = run_migrations_enabled
if prompts_enabled and run_migrations_enabled: if prompts_enabled and run_migrations_enabled:
proceed_with_sending_invites = TerminalHelper.query_yes_no( proceed_with_sending_invites = TerminalHelper.query_yes_no(
f"""{TerminalColors.FAIL} f"""{TerminalColors.FAIL}
Proceed with sending user invites? Proceed with sending user invites for all transition domains?
(Y = proceed, N = skip) (Y = proceed, N = skip)
{TerminalColors.ENDC}""" {TerminalColors.ENDC}"""
) )

View file

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

View file

@ -1,3 +1,4 @@
from unittest.mock import patch
from django.test import TestCase from django.test import TestCase
from registrar.models import ( 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.master_domain_migrations import Command as master_migration_command
from django.core.management import call_command
from registrar.management.commands.utility.terminal_helper import (
TerminalHelper,
)
class TestLogins(TestCase): class TestLogins(TestCase):
"""Test ......""" """ """
def setUp(self): 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 self.test_data_file_location = "/app/registrar/tests/data"
# UserDomainRole.objects.all().delete() 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): def tearDown(self):
super().tearDown() super().tearDown()
@ -32,6 +34,29 @@ class TestLogins(TestCase):
Domain.objects.all().delete() Domain.objects.all().delete()
DomainInvitation.objects.all().delete() DomainInvitation.objects.all().delete()
DomainInformation.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, def compare_tables(self,
expected_total_transition_domains, expected_total_transition_domains,
@ -102,6 +127,7 @@ class TestLogins(TestCase):
self.assertTrue(total_domains == expected_total_domains) self.assertTrue(total_domains == expected_total_domains)
self.assertTrue(total_domain_informations == expected_total_domain_informations) self.assertTrue(total_domain_informations == expected_total_domain_informations)
self.assertTrue(total_domain_invitations == expected_total_domain_invitations) self.assertTrue(total_domain_invitations == expected_total_domain_invitations)
def test_master_migration_functions(self): def test_master_migration_functions(self):
""" Run the full master migration script using local test data. """ Run the full master migration script using local test data.
@ -110,28 +136,23 @@ class TestLogins(TestCase):
But for now, this will double-check that the script But for now, this will double-check that the script
works as intended. """ works as intended. """
migration_directory = "/app/registrar/tests/data/" self.run_master_script()
contacts_filename = "test_contacts.txt"
domain_contacts_filename = "test_domain_contacts.txt"
domain_statuses_filename = "test_domain_statuses.txt"
# STEP 1: Run the master migration script using local test data # TODO: instead of patching....there has got to be a way of making sure subsequent commands use the django database
master_migration_command.run_load_transition_domain_script(master_migration_command(), # Patch subroutines for migrations
migration_directory, def side_effect():
domain_contacts_filename, self.run_load_domains()
contacts_filename, self.run_transfer_domains()
domain_statuses_filename, patcher = patch("registrar.management.commands.master_domain_migrations.Command.run_migration_scripts")
"|", mocked_get = patcher.start()
False, mocked_get.side_effect = side_effect
False, # Patch subroutines for sending invitations
False, def side_effect():
0) # TODO: what should happen here?
return
# run_master_script_command = "./manage.py master_domain_migrations" patcher = patch("registrar.management.commands.master_domain_migrations.Command.run_send_invites_script")
# run_master_script_command += " --runMigrations" mocked_get = patcher.start()
# run_master_script_command += " --migrationDirectory /app/registrar/tests/data" mocked_get.side_effect = side_effect
# run_master_script_command += " --migrationFilenames test_contacts.txt,test_domain_contacts.txt,test_domain_statuses.txt"
# TerminalHelper.execute_command(run_master_script_command)
# STEP 2: (analyze the tables just like the migration script does, but add assert statements) # STEP 2: (analyze the tables just like the migration script does, but add assert statements)
expected_total_transition_domains = 8 expected_total_transition_domains = 8
@ -154,11 +175,85 @@ class TestLogins(TestCase):
expected_missing_domain_informations, expected_missing_domain_informations,
expected_missing_domain_invitations, expected_missing_domain_invitations,
) )
def test_load_transition_domain(self):
self.run_load_domains()
def test_load_transition_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
def test_user_logins(self): expected_missing_domains = 8
"""A new user's first_login callback retrieves their invitations.""" expected_duplicate_domains = 0
# self.user.first_login() expected_missing_domain_informations = 8
# self.assertTrue(UserDomainRole.objects.get(user=self.user, domain=self.domain)) 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,
)