From 6022cd051fd8e11887dc9e517f2be05b76b0df52 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 13:50:59 -0600 Subject: [PATCH 01/13] Add first ready on field --- src/registrar/utility/csv_export.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 8787f9e74..7fcbae475 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -96,6 +96,7 @@ def parse_row_for_domain( FIELDS = { "Domain name": domain.name, "Status": domain.get_state_display(), + "First ready on": domain.first_ready, "Expiration date": domain.expiration_date, "Domain type": domain_type, "Agency": domain_info.federal_agency, @@ -106,7 +107,6 @@ def parse_row_for_domain( "AO email": domain_info.authorizing_official.email if domain_info.authorizing_official else " ", "Security contact email": security_email, "Created at": domain.created_at, - "First ready": domain.first_ready, "Deleted": domain.deleted, } @@ -378,13 +378,17 @@ def write_csv_for_requests( def export_data_type_to_csv(csv_file): - """All domains report with extra columns""" + """ + All domains report with extra columns. + This maps to the "All domain metadata" button. + """ writer = csv.writer(csv_file) # define columns to include in export columns = [ "Domain name", "Status", + "First ready on", "Expiration date", "Domain type", "Agency", From 6a3eb005bcea300ad5271da6d7676468ce410c3b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:04:00 -0600 Subject: [PATCH 02/13] Update csv_export.py --- src/registrar/utility/csv_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 7fcbae475..f4a079d20 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -96,7 +96,7 @@ def parse_row_for_domain( FIELDS = { "Domain name": domain.name, "Status": domain.get_state_display(), - "First ready on": domain.first_ready, + "First ready on": domain.first_ready or "(blank)", "Expiration date": domain.expiration_date, "Domain type": domain_type, "Agency": domain_info.federal_agency, From f7208a80ea467d032a6cf57dc0ad0321fec7af61 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:36:08 -0600 Subject: [PATCH 03/13] Add unit test and move things around slightly --- src/registrar/tests/test_reports.py | 240 +++++++++++++++------------- 1 file changed, 125 insertions(+), 115 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index d918dda92..7a11c18c0 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -25,6 +25,56 @@ from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # typ from datetime import datetime from django.utils import timezone from .common import MockDb, MockEppLib, less_console_noise +from api.tests.common import less_console_noise_decorator + + +class HelperFunctions(MockDb): + """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" + + def get_time_aware_date(self, date=datetime(2023, 11, 1)): + """Returns a time aware date""" + return timezone.make_aware(date) + + def test_get_default_start_date(self): + expected_date = self.get_time_aware_date() + actual_date = get_default_start_date() + self.assertEqual(actual_date, expected_date) + + def test_get_default_end_date(self): + # Note: You may need to mock timezone.now() for accurate testing + expected_date = timezone.now() + actual_date = get_default_end_date() + self.assertEqual(actual_date.date(), expected_date.date()) + + def test_get_sliced_domains(self): + """Should get fitered domains counts sliced by org type and election office.""" + + with less_console_noise(): + filter_condition = { + "domain__permissions__isnull": False, + "domain__first_ready__lte": self.end_date, + } + # Test with distinct + managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) + expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(managed_domains_sliced_at_end_date, expected_content) + + # Test without distinct + managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) + expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(managed_domains_sliced_at_end_date, expected_content) + + def test_get_sliced_requests(self): + """Should get fitered requests counts sliced by org type and election office.""" + + with less_console_noise(): + filter_condition = { + "status": DomainRequest.DomainRequestStatus.SUBMITTED, + "submission_date__lte": self.end_date, + } + submitted_requests_sliced_at_end_date = get_sliced_requests(filter_condition) + expected_content = [2, 2, 0, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(submitted_requests_sliced_at_end_date, expected_content) class CsvReportsTest(MockDb): @@ -194,84 +244,89 @@ class CsvReportsTest(MockDb): self.assertEqual(expected_file_content, response.content) -class ExportDataTest(MockDb, MockEppLib): +class ExportDataTest(HelperFunctions, MockEppLib): def setUp(self): super().setUp() def tearDown(self): super().tearDown() - - def test_export_domains_to_writer_security_emails(self): + + @less_console_noise_decorator + def test_export_domains_to_writer_security_emails_and_first_ready(self): """Test that export_domains_to_writer returns the - expected security email""" + expected security email and first_ready value""" + # 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 - 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_csv_for_domains( - writer, - columns, - sort_fields, - filter_condition, - should_get_domain_managers=False, - should_write_header=True, - ) + # Add a first ready date on the first domain. Leaving the others blank. + self.domain_1.first_ready = get_default_start_date() + self.domain_1.save() - # 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" - "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady\n" - "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15\n" - "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready\n" - "zdomain12.govInterstateReady\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) + # 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", + "First ready on", + ] + 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_csv_for_domains( + writer, + columns, + sort_fields, + filter_condition, + should_get_domain_managers=False, + should_write_header=True, + ) + + # 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, First ready on\n" + "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,2024-05-09\n" + "adomain2.gov,Interstate,(blank),Dns needed,(blank)\n" + "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady,2024-05-08\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15,(blank)\n" + "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,2023-11-01\n" + "zdomain12.govInterstateReady,2024-05-08\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_csv_for_domains(self): """Test that write_body returns the @@ -692,48 +747,3 @@ class ExportDataTest(MockDb, MockEppLib): expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip() self.assertEqual(csv_content, expected_content) - - -class HelperFunctions(MockDb): - """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" - - def test_get_default_start_date(self): - expected_date = timezone.make_aware(datetime(2023, 11, 1)) - actual_date = get_default_start_date() - self.assertEqual(actual_date, expected_date) - - def test_get_default_end_date(self): - # Note: You may need to mock timezone.now() for accurate testing - expected_date = timezone.now() - actual_date = get_default_end_date() - self.assertEqual(actual_date.date(), expected_date.date()) - - def test_get_sliced_domains(self): - """Should get fitered domains counts sliced by org type and election office.""" - - with less_console_noise(): - filter_condition = { - "domain__permissions__isnull": False, - "domain__first_ready__lte": self.end_date, - } - # Test with distinct - managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) - expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(managed_domains_sliced_at_end_date, expected_content) - - # Test without distinct - managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) - expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(managed_domains_sliced_at_end_date, expected_content) - - def test_get_sliced_requests(self): - """Should get fitered requests counts sliced by org type and election office.""" - - with less_console_noise(): - filter_condition = { - "status": DomainRequest.DomainRequestStatus.SUBMITTED, - "submission_date__lte": self.end_date, - } - submitted_requests_sliced_at_end_date = get_sliced_requests(filter_condition) - expected_content = [2, 2, 0, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(submitted_requests_sliced_at_end_date, expected_content) From 5c685a3fd6b39400ade3bed16b7f18713673abfa Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:41:19 -0600 Subject: [PATCH 04/13] Cleanup --- src/registrar/tests/common.py | 4 + src/registrar/tests/test_reports.py | 239 ++++++++++++++-------------- 2 files changed, 121 insertions(+), 122 deletions(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 3d9a147a2..ba1c75dce 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -746,6 +746,10 @@ class MockDb(TestCase): DomainInvitation.objects.all().delete() FederalAgency.objects.all().delete() + def get_time_aware_date(self, date=datetime(2023, 11, 1)): + """Returns a time aware date""" + return timezone.make_aware(date) + def mock_user(): """A simple user.""" diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 7a11c18c0..0c9e1d6c4 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -25,56 +25,6 @@ from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # typ from datetime import datetime from django.utils import timezone from .common import MockDb, MockEppLib, less_console_noise -from api.tests.common import less_console_noise_decorator - - -class HelperFunctions(MockDb): - """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" - - def get_time_aware_date(self, date=datetime(2023, 11, 1)): - """Returns a time aware date""" - return timezone.make_aware(date) - - def test_get_default_start_date(self): - expected_date = self.get_time_aware_date() - actual_date = get_default_start_date() - self.assertEqual(actual_date, expected_date) - - def test_get_default_end_date(self): - # Note: You may need to mock timezone.now() for accurate testing - expected_date = timezone.now() - actual_date = get_default_end_date() - self.assertEqual(actual_date.date(), expected_date.date()) - - def test_get_sliced_domains(self): - """Should get fitered domains counts sliced by org type and election office.""" - - with less_console_noise(): - filter_condition = { - "domain__permissions__isnull": False, - "domain__first_ready__lte": self.end_date, - } - # Test with distinct - managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) - expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(managed_domains_sliced_at_end_date, expected_content) - - # Test without distinct - managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) - expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(managed_domains_sliced_at_end_date, expected_content) - - def test_get_sliced_requests(self): - """Should get fitered requests counts sliced by org type and election office.""" - - with less_console_noise(): - filter_condition = { - "status": DomainRequest.DomainRequestStatus.SUBMITTED, - "submission_date__lte": self.end_date, - } - submitted_requests_sliced_at_end_date = get_sliced_requests(filter_condition) - expected_content = [2, 2, 0, 0, 0, 0, 0, 0, 0, 0] - self.assertEqual(submitted_requests_sliced_at_end_date, expected_content) class CsvReportsTest(MockDb): @@ -244,89 +194,89 @@ class CsvReportsTest(MockDb): self.assertEqual(expected_file_content, response.content) -class ExportDataTest(HelperFunctions, MockEppLib): +class ExportDataTest(MockDb, MockEppLib): def setUp(self): super().setUp() def tearDown(self): super().tearDown() - - @less_console_noise_decorator + def test_export_domains_to_writer_security_emails_and_first_ready(self): """Test that export_domains_to_writer returns the expected security email and first_ready value""" - # 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 + 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 - # Add a first ready date on the first domain. Leaving the others blank. - self.domain_1.first_ready = get_default_start_date() - self.domain_1.save() + # Add a first ready date on the first domain. Leaving the others blank. + self.domain_1.first_ready = get_default_start_date() + self.domain_1.save() - # 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", - "First ready on", - ] - 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_csv_for_domains( - writer, - columns, - sort_fields, - filter_condition, - should_get_domain_managers=False, - should_write_header=True, - ) + # 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", + "First ready on", + ] + 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_csv_for_domains( + writer, + columns, + sort_fields, + filter_condition, + should_get_domain_managers=False, + should_write_header=True, + ) - # 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, First ready on\n" - "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,2024-05-09\n" - "adomain2.gov,Interstate,(blank),Dns needed,(blank)\n" - "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady,2024-05-08\n" - "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15,(blank)\n" - "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,2023-11-01\n" - "zdomain12.govInterstateReady,2024-05-08\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) + # 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, First ready on\n" + "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,2024-05-09\n" + "adomain2.gov,Interstate,(blank),Dns needed,(blank)\n" + "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady,2024-05-08\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15,(blank)\n" + "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,2023-11-01\n" + "zdomain12.govInterstateReady,2024-05-08\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_csv_for_domains(self): """Test that write_body returns the @@ -747,3 +697,48 @@ class ExportDataTest(HelperFunctions, MockEppLib): expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip() self.assertEqual(csv_content, expected_content) + + +class HelperFunctions(MockDb): + """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" + + def test_get_default_start_date(self): + expected_date = self.get_time_aware_date() + actual_date = get_default_start_date() + self.assertEqual(actual_date, expected_date) + + def test_get_default_end_date(self): + # Note: You may need to mock timezone.now() for accurate testing + expected_date = timezone.now() + actual_date = get_default_end_date() + self.assertEqual(actual_date.date(), expected_date.date()) + + def test_get_sliced_domains(self): + """Should get fitered domains counts sliced by org type and election office.""" + + with less_console_noise(): + filter_condition = { + "domain__permissions__isnull": False, + "domain__first_ready__lte": self.end_date, + } + # Test with distinct + managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) + expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(managed_domains_sliced_at_end_date, expected_content) + + # Test without distinct + managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition) + expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(managed_domains_sliced_at_end_date, expected_content) + + def test_get_sliced_requests(self): + """Should get fitered requests counts sliced by org type and election office.""" + + with less_console_noise(): + filter_condition = { + "status": DomainRequest.DomainRequestStatus.SUBMITTED, + "submission_date__lte": self.end_date, + } + submitted_requests_sliced_at_end_date = get_sliced_requests(filter_condition) + expected_content = [2, 2, 0, 0, 0, 0, 0, 0, 0, 0] + self.assertEqual(submitted_requests_sliced_at_end_date, expected_content) From fda321b02a3c4a544175bc24dac165ed06d4748d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:43:51 -0600 Subject: [PATCH 05/13] Update src/registrar/tests/test_reports.py --- src/registrar/tests/test_reports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 0c9e1d6c4..7d88c9b30 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -204,6 +204,7 @@ class ExportDataTest(MockDb, MockEppLib): def test_export_domains_to_writer_security_emails_and_first_ready(self): """Test that export_domains_to_writer returns the expected security email and first_ready value""" + with less_console_noise: # Add security email information self.domain_1.name = "defaultsecurity.gov" From 460388ea57089fddcebfa17d12aa00caa1d57eb3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:46:24 -0600 Subject: [PATCH 06/13] Update test_reports.py --- src/registrar/tests/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 7d88c9b30..aa21635e3 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -205,7 +205,7 @@ class ExportDataTest(MockDb, MockEppLib): """Test that export_domains_to_writer returns the expected security email and first_ready value""" - with less_console_noise: + with less_console_noise(): # Add security email information self.domain_1.name = "defaultsecurity.gov" self.domain_1.save() From ceed417aebdaafbe4b80ba887aacfc34c9940f8b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 8 May 2024 14:52:16 -0600 Subject: [PATCH 07/13] Update test_reports.py --- src/registrar/tests/test_reports.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index aa21635e3..430e04d6c 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -22,7 +22,6 @@ from django.conf import settings from botocore.exceptions import ClientError import boto3_mocking from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore -from datetime import datetime from django.utils import timezone from .common import MockDb, MockEppLib, less_console_noise From a1ac715281a6f6bc17c5f282f2ae715e62989904 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 9 May 2024 08:17:43 -0600 Subject: [PATCH 08/13] Add blank check on expiration date --- src/registrar/utility/csv_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index f4a079d20..283c884f9 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -97,7 +97,7 @@ def parse_row_for_domain( "Domain name": domain.name, "Status": domain.get_state_display(), "First ready on": domain.first_ready or "(blank)", - "Expiration date": domain.expiration_date, + "Expiration date": domain.expiration_date or "(blank)", "Domain type": domain_type, "Agency": domain_info.federal_agency, "Organization name": domain_info.organization_name, From 4618f302f5a57f3bfb9117f5463174c8c8d974a1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 9 May 2024 09:21:53 -0600 Subject: [PATCH 09/13] Adjust unit tests to not be time sensitive The first ready field was using timezone.now() which is not good when directly testing that field. This is a minor refactor which just sets a preset time as "now" and adjusted the unit tests minorly to compensate --- src/registrar/tests/common.py | 54 +++++++++++++++++------------ src/registrar/tests/test_reports.py | 52 ++++++++++++++------------- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index ba1c75dce..be7065403 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -97,6 +97,11 @@ def less_console_noise(output_stream=None): output_stream.close() +def get_time_aware_date(date=datetime(2023, 11, 1)): + """Returns a time aware date""" + return timezone.make_aware(date) + + class GenericTestHelper(TestCase): """A helper class that contains various helper functions for TestCases""" @@ -532,11 +537,9 @@ class MockDb(TestCase): username=username, first_name=first_name, last_name=last_name, email=email ) - # Create a time-aware current date - current_datetime = timezone.now() - # Extract the date part - current_date = current_datetime.date() + current_date = get_time_aware_date(datetime(2024, 4, 2)) # Create start and end dates using timedelta + self.end_date = current_date + timedelta(days=2) self.start_date = current_date - timedelta(days=2) @@ -544,22 +547,22 @@ class MockDb(TestCase): self.federal_agency_2, _ = FederalAgency.objects.get_or_create(agency="Armed Forces Retirement Home") self.domain_1, _ = Domain.objects.get_or_create( - name="cdomain1.gov", state=Domain.State.READY, first_ready=timezone.now() + name="cdomain1.gov", state=Domain.State.READY, first_ready=get_time_aware_date(datetime(2024, 4, 2)) ) self.domain_2, _ = Domain.objects.get_or_create(name="adomain2.gov", state=Domain.State.DNS_NEEDED) self.domain_3, _ = Domain.objects.get_or_create(name="ddomain3.gov", state=Domain.State.ON_HOLD) self.domain_4, _ = Domain.objects.get_or_create(name="bdomain4.gov", state=Domain.State.UNKNOWN) self.domain_5, _ = Domain.objects.get_or_create( - name="bdomain5.gov", state=Domain.State.DELETED, deleted=timezone.make_aware(datetime(2023, 11, 1)) + name="bdomain5.gov", state=Domain.State.DELETED, deleted=get_time_aware_date(datetime(2023, 11, 1)) ) self.domain_6, _ = Domain.objects.get_or_create( - name="bdomain6.gov", state=Domain.State.DELETED, deleted=timezone.make_aware(datetime(1980, 10, 16)) + name="bdomain6.gov", state=Domain.State.DELETED, deleted=get_time_aware_date(datetime(1980, 10, 16)) ) self.domain_7, _ = Domain.objects.get_or_create( - name="xdomain7.gov", state=Domain.State.DELETED, deleted=timezone.now() + name="xdomain7.gov", state=Domain.State.DELETED, deleted=get_time_aware_date(datetime(2024, 4, 2)) ) self.domain_8, _ = Domain.objects.get_or_create( - name="sdomain8.gov", state=Domain.State.DELETED, deleted=timezone.now() + name="sdomain8.gov", state=Domain.State.DELETED, deleted=get_time_aware_date(datetime(2024, 4, 2)) ) # 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()). @@ -567,19 +570,19 @@ class MockDb(TestCase): self.domain_9, _ = Domain.objects.get_or_create( name="zdomain9.gov", state=Domain.State.DELETED, - deleted=timezone.make_aware(datetime.combine(date.today() - timedelta(days=1), datetime.min.time())), + deleted=get_time_aware_date(datetime(2024, 4, 1)), ) # ready tomorrow self.domain_10, _ = Domain.objects.get_or_create( name="adomain10.gov", state=Domain.State.READY, - first_ready=timezone.make_aware(datetime.combine(date.today() + timedelta(days=1), datetime.min.time())), + first_ready=get_time_aware_date(datetime(2024, 4, 3)), ) self.domain_11, _ = Domain.objects.get_or_create( - name="cdomain11.gov", state=Domain.State.READY, first_ready=timezone.now() + name="cdomain11.gov", state=Domain.State.READY, first_ready=get_time_aware_date(datetime(2024, 4, 2)) ) self.domain_12, _ = Domain.objects.get_or_create( - name="zdomain12.gov", state=Domain.State.READY, first_ready=timezone.now() + name="zdomain12.gov", state=Domain.State.READY, first_ready=get_time_aware_date(datetime(2024, 4, 2)) ) self.domain_information_1, _ = DomainInformation.objects.get_or_create( @@ -716,23 +719,31 @@ class MockDb(TestCase): with less_console_noise(): self.domain_request_1 = completed_domain_request( - status=DomainRequest.DomainRequestStatus.STARTED, name="city1.gov" + status=DomainRequest.DomainRequestStatus.STARTED, + name="city1.gov", ) self.domain_request_2 = completed_domain_request( - status=DomainRequest.DomainRequestStatus.IN_REVIEW, name="city2.gov" + status=DomainRequest.DomainRequestStatus.IN_REVIEW, + name="city2.gov", ) self.domain_request_3 = completed_domain_request( - status=DomainRequest.DomainRequestStatus.STARTED, name="city3.gov" + status=DomainRequest.DomainRequestStatus.STARTED, + name="city3.gov", ) self.domain_request_4 = completed_domain_request( - status=DomainRequest.DomainRequestStatus.STARTED, name="city4.gov" + status=DomainRequest.DomainRequestStatus.STARTED, + name="city4.gov", ) self.domain_request_5 = completed_domain_request( - status=DomainRequest.DomainRequestStatus.APPROVED, name="city5.gov" + status=DomainRequest.DomainRequestStatus.APPROVED, + name="city5.gov", ) self.domain_request_3.submit() - self.domain_request_3.save() self.domain_request_4.submit() + + self.domain_request_3.submission_date = get_time_aware_date(datetime(2024, 4, 2)) + self.domain_request_4.submission_date = get_time_aware_date(datetime(2024, 4, 2)) + self.domain_request_3.save() self.domain_request_4.save() def tearDown(self): @@ -746,10 +757,6 @@ class MockDb(TestCase): DomainInvitation.objects.all().delete() FederalAgency.objects.all().delete() - def get_time_aware_date(self, date=datetime(2023, 11, 1)): - """Returns a time aware date""" - return timezone.make_aware(date) - def mock_user(): """A simple user.""" @@ -877,6 +884,7 @@ def completed_domain_request( if organization_type: domain_request_kwargs["organization_type"] = organization_type + domain_request, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs) if has_other_contacts: diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 430e04d6c..9923df85d 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -23,7 +23,7 @@ from botocore.exceptions import ClientError import boto3_mocking from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore from django.utils import timezone -from .common import MockDb, MockEppLib, less_console_noise +from .common import MockDb, MockEppLib, less_console_noise, get_time_aware_date class CsvReportsTest(MockDb): @@ -265,12 +265,12 @@ class ExportDataTest(MockDb, MockEppLib): expected_content = ( "Domain name,Domain type,Agency,Organization name,City,State,AO," "AO email,Security contact email,Status,Expiration date, First ready on\n" - "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,2024-05-09\n" - "adomain2.gov,Interstate,(blank),Dns needed,(blank)\n" - "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady,2024-05-08\n" + "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,(blank),2023-11-01\n" + "adomain2.gov,Interstate,(blank),Dns needed,(blank),(blank)\n" + "cdomain11.gov,Federal-Executive,WorldWarICentennialCommission,Ready,(blank),2023-11-01\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15,(blank)\n" - "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,2023-11-01\n" - "zdomain12.govInterstateReady,2024-05-08\n" + "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,(blank),2023-11-01\n" + "zdomain12.govInterstateReady,(blank),2023-11-01\n" ) # Normalize line endings and remove commas, # spaces and leading/trailing whitespace @@ -474,19 +474,21 @@ class ExportDataTest(MockDb, MockEppLib): # 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 + self.maxDiff = None + # We expect READY domains first, created between day-2 and day+2, sorted by created_at then name + # and DELETED domains deleted between day-2 and day+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" - "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady\n" - "zdomain12.govInterstateReady\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" + "cdomain1.gov,Federal-Executive,World War I Centennial Commission,,,,Ready,(blank)\n" + "adomain10.gov,Federal,Armed Forces Retirement Home,,,,Ready,(blank)\n" + "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady(blank)\n" + "zdomain12.govInterstateReady(blank)\n" + "bdomain5.gov,Federal,ArmedForcesRetirementHome,Deleted(blank)\n" + "bdomain6.gov,Federal,ArmedForcesRetirementHome,Deleted,(blank)\n" + "sdomain8.gov,Federal,Armed Forces Retirement Home,,,,Deleted,(blank)\n" + "xdomain7.gov,Federal,Armed Forces Retirement Home,,,,Deleted,(blank)\n" + "zdomain9.gov,Federal,ArmedForcesRetirementHome,Deleted,(blank)\n" ) # Normalize line endings and remove commas, @@ -531,7 +533,7 @@ class ExportDataTest(MockDb, MockEppLib): Domain.State.ON_HOLD, ], } - self.maxDiff = None + # Call the export functions write_csv_for_domains( writer, @@ -553,14 +555,14 @@ class ExportDataTest(MockDb, MockEppLib): "Organization name,City,State,AO,AO email," "Security contact email,Domain manager 1,DM1 status,Domain manager 2,DM2 status," "Domain manager 3,DM3 status,Domain manager 4,DM4 status\n" - "adomain10.gov,Ready,,Federal,Armed Forces Retirement Home,,,, , ,squeaker@rocks.com, I\n" - "adomain2.gov,Dns needed,,Interstate,,,,, , , ,meoward@rocks.com, R,squeaker@rocks.com, I\n" - "cdomain11.govReadyFederal-ExecutiveWorldWarICentennialCommissionmeoward@rocks.comR\n" - "cdomain1.gov,Ready,,Federal - Executive,World War I Centennial Commission,,," + "adomain10.gov,Ready,(blank),Federal,Armed Forces Retirement Home,,,, , ,squeaker@rocks.com, I\n" + "adomain2.gov,Dns needed,(blank),Interstate,,,,, , , ,meoward@rocks.com, R,squeaker@rocks.com, I\n" + "cdomain11.govReady,(blank),Federal-ExecutiveWorldWarICentennialCommissionmeoward@rocks.comR\n" + "cdomain1.gov,Ready,(blank),Federal - Executive,World War I Centennial Commission,,," ", , , ,meoward@rocks.com,R,info@example.com,R,big_lebowski@dude.co,R," "woofwardthethird@rocks.com,I\n" - "ddomain3.gov,On hold,,Federal,Armed Forces Retirement Home,,,, , , ,,\n" - "zdomain12.govReadyInterstatemeoward@rocks.comR\n" + "ddomain3.gov,On hold,(blank),Federal,Armed Forces Retirement Home,,,, , , ,,\n" + "zdomain12.gov,Ready,(blank),Interstate,meoward@rocks.com,R\n" ) # Normalize line endings and remove commas, # spaces and leading/trailing whitespace @@ -695,7 +697,7 @@ class ExportDataTest(MockDb, MockEppLib): # 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() - + print(f"what is the actual content {csv_content}") self.assertEqual(csv_content, expected_content) @@ -703,7 +705,7 @@ class HelperFunctions(MockDb): """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" def test_get_default_start_date(self): - expected_date = self.get_time_aware_date() + expected_date = get_time_aware_date() actual_date = get_default_start_date() self.assertEqual(actual_date, expected_date) From 8af790293929a5eeb544e44dd81cbe697c88d741 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 9 May 2024 09:23:17 -0600 Subject: [PATCH 10/13] Remove max diff --- src/registrar/tests/test_admin.py | 1 - src/registrar/tests/test_reports.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 98c5df0ac..e85c2fc5e 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -2164,7 +2164,6 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Yes, select ineligible status") def test_readonly_when_restricted_creator(self): - self.maxDiff = None with less_console_noise(): domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 9923df85d..bdfddf534 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -245,7 +245,7 @@ class ExportDataTest(MockDb, MockEppLib): Domain.State.ON_HOLD, ], } - self.maxDiff = None + # Call the export functions write_csv_for_domains( writer, @@ -474,7 +474,7 @@ class ExportDataTest(MockDb, MockEppLib): # Read the content into a variable csv_content = csv_file.read() - self.maxDiff = None + # We expect READY domains first, created between day-2 and day+2, sorted by created_at then name # and DELETED domains deleted between day-2 and day+2, sorted by deleted then name expected_content = ( @@ -587,7 +587,7 @@ class ExportDataTest(MockDb, MockEppLib): csv_file.seek(0) # Read the content into a variable csv_content = csv_file.read() - self.maxDiff = None + # We expect the READY domain names with the domain managers: Their counts, and listing at end_date. expected_content = ( "MANAGED DOMAINS COUNTS AT START DATE\n" @@ -630,7 +630,7 @@ class ExportDataTest(MockDb, MockEppLib): csv_file.seek(0) # Read the content into a variable csv_content = csv_file.read() - self.maxDiff = None + # We expect the READY domain names with the domain managers: Their counts, and listing at end_date. expected_content = ( "UNMANAGED DOMAINS AT START DATE\n" From 0ac79da907597028664ab513cb85dce0b8e9294d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 9 May 2024 09:23:41 -0600 Subject: [PATCH 11/13] Remove print --- src/registrar/tests/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index bdfddf534..7337db15d 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -697,7 +697,7 @@ class ExportDataTest(MockDb, MockEppLib): # 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() - print(f"what is the actual content {csv_content}") + self.assertEqual(csv_content, expected_content) From e23c3eee52211450091e185f1aca0973188dd212 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 9 May 2024 13:56:13 -0600 Subject: [PATCH 12/13] Fix tests and lint --- src/registrar/tests/test_reports.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 7337db15d..e214ec0ee 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -265,12 +265,13 @@ class ExportDataTest(MockDb, MockEppLib): expected_content = ( "Domain name,Domain type,Agency,Organization name,City,State,AO," "AO email,Security contact email,Status,Expiration date, First ready on\n" - "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,(blank),2023-11-01\n" + "adomain10.gov,Federal,Armed Forces Retirement Home,Ready,(blank),2024-04-03\n" "adomain2.gov,Interstate,(blank),Dns needed,(blank),(blank)\n" - "cdomain11.gov,Federal-Executive,WorldWarICentennialCommission,Ready,(blank),2023-11-01\n" + "cdomain11.gov,Federal-Executive,WorldWarICentennialCommission,Ready,(blank),2024-04-02\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,security@mail.gov,On hold,2023-11-15,(blank)\n" - "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready,(blank),2023-11-01\n" - "zdomain12.govInterstateReady,(blank),2023-11-01\n" + "defaultsecurity.gov,Federal - Executive,World War I Centennial Commission," + "(blank),Ready,(blank),2023-11-01\n" + "zdomain12.govInterstateReady,(blank),2024-04-02\n" ) # Normalize line endings and remove commas, # spaces and leading/trailing whitespace @@ -474,7 +475,7 @@ class ExportDataTest(MockDb, MockEppLib): # Read the content into a variable csv_content = csv_file.read() - + self.maxDiff = None # We expect READY domains first, created between day-2 and day+2, sorted by created_at then name # and DELETED domains deleted between day-2 and day+2, sorted by deleted then name expected_content = ( @@ -484,11 +485,9 @@ class ExportDataTest(MockDb, MockEppLib): "adomain10.gov,Federal,Armed Forces Retirement Home,,,,Ready,(blank)\n" "cdomain11.govFederal-ExecutiveWorldWarICentennialCommissionReady(blank)\n" "zdomain12.govInterstateReady(blank)\n" - "bdomain5.gov,Federal,ArmedForcesRetirementHome,Deleted(blank)\n" - "bdomain6.gov,Federal,ArmedForcesRetirementHome,Deleted,(blank)\n" - "sdomain8.gov,Federal,Armed Forces Retirement Home,,,,Deleted,(blank)\n" - "xdomain7.gov,Federal,Armed Forces Retirement Home,,,,Deleted,(blank)\n" "zdomain9.gov,Federal,ArmedForcesRetirementHome,Deleted,(blank)\n" + "sdomain8.gov,Federal,Armed Forces Retirement Home,,,,Deleted,(blank)\n" + "xdomain7.gov,FederalArmedForcesRetirementHome,Deleted,(blank)\n" ) # Normalize line endings and remove commas, From 45af1f10e5e225075bc1ca6925526bd34b418a49 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 10 May 2024 08:33:34 -0600 Subject: [PATCH 13/13] Cleanup --- src/registrar/tests/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index e214ec0ee..4f308b2b6 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -475,7 +475,7 @@ class ExportDataTest(MockDb, MockEppLib): # Read the content into a variable csv_content = csv_file.read() - self.maxDiff = None + # We expect READY domains first, created between day-2 and day+2, sorted by created_at then name # and DELETED domains deleted between day-2 and day+2, sorted by deleted then name expected_content = (