diff --git a/docs/developer/README.md b/docs/developer/README.md index d58dd31ad..cd33aeea6 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -78,6 +78,21 @@ To test behind logged in pages with external tools, like `pa11y-ci` or `OWASP Za to MIDDLEWARE in settings.py. **Remove it when you are finished testing.** +### Reducing console noise in tests + +Some tests, particularly when using Django's test client, will print errors. + +These errors do not indicate test failure, but can make the output hard to read. + +To silence them, we have a helper function `less_console_noise`: + +```python +from .common import less_console_noise +... + with less_console_noise(): + # +``` + ### Accessibility Scanning The tool `pa11y-ci` is used to scan pages for compliance with a set of diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index b5a2255c7..12a8507f7 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -36,7 +36,12 @@ class Domain(TimeStampedModel): ] class Status(models.TextChoices): - """The status codes we can receive from the registry.""" + """ + The status codes we can receive from the registry. + + These are detailed in RFC 5731 in section 2.3. + https://www.rfc-editor.org/std/std69.txt + """ # Requests to delete the object MUST be rejected. CLIENT_DELETE_PROHIBITED = "clientDeleteProhibited" @@ -96,7 +101,9 @@ class Domain(TimeStampedModel): @classmethod def available(cls, domain: str) -> bool: - """Check if a domain is available. Not implemented.""" + """Check if a domain is available. + + Not implemented. Returns a dummy value for testing.""" return domain_check(domain) def transfer(self): @@ -119,9 +126,15 @@ class Domain(TimeStampedModel): logger.error(e) # TODO: back off error handling return None - if hasattr(self, "info") and (property in self.info): - return self.info[property] + if hasattr(self, "info"): + if property in self.info: + return self.info[property] + else: + raise KeyError( + "Requested key %s was not found in registry data." % str(property) + ) else: + # TODO: return an error if registry cannot be contacted return None def could_be_domain(self) -> bool: diff --git a/src/registrar/models/host.py b/src/registrar/models/host.py index 132e72792..23f6c7659 100644 --- a/src/registrar/models/host.py +++ b/src/registrar/models/host.py @@ -28,5 +28,6 @@ class Host(TimeStampedModel): domain = models.ForeignKey( Domain, on_delete=models.PROTECT, + related_name="host", # access this Host via the Domain as `domain.host` help_text="Domain to which this host belongs", ) diff --git a/src/registrar/models/host_ip.py b/src/registrar/models/host_ip.py index c6aa1a3c8..22847b77c 100644 --- a/src/registrar/models/host_ip.py +++ b/src/registrar/models/host_ip.py @@ -27,5 +27,6 @@ class HostIP(TimeStampedModel): host = models.ForeignKey( Host, on_delete=models.PROTECT, + related_name="ip", # access this HostIP via the Host as `host.ip` help_text="Host to which this IP address belongs", ) diff --git a/src/registrar/models/nameserver.py b/src/registrar/models/nameserver.py index 913b3ab03..13295f5b5 100644 --- a/src/registrar/models/nameserver.py +++ b/src/registrar/models/nameserver.py @@ -11,4 +11,6 @@ class Nameserver(Host): before their application is approved. """ + # there is nothing here because all of the fields are + # defined over there on the Host class pass diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 78d4cb196..535ab9360 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -2,6 +2,7 @@ from django.test import TestCase from django.db.utils import IntegrityError from registrar.models import Contact, DomainApplication, User, Website, Domain +from unittest import skip class TestDomainApplication(TestCase): @@ -86,7 +87,7 @@ class TestDomain(TestCase): self.assertIn("ok", domain.status) def test_fsm_activate_fail_unique(self): - # can't activate domain if name is not unique + """Can't activate domain if name is not unique.""" d1, _ = Domain.objects.get_or_create(name="igorville.gov") d2, _ = Domain.objects.get_or_create(name="igorville.gov") d1.activate() @@ -95,7 +96,7 @@ class TestDomain(TestCase): d2.activate() def test_fsm_activate_fail_unapproved(self): - # can't activate domain if application isn't approved + """Can't activate domain if application isn't approved.""" d1, _ = Domain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() application = DomainApplication.objects.create(creator=user) @@ -103,3 +104,55 @@ class TestDomain(TestCase): d1.save() with self.assertRaises(ValueError): d1.activate() + + +@skip("Not implemented yet.") +class TestDomainApplicationLifeCycle(TestCase): + def test_application_approval(self): + # DomainApplication is created + # test: Domain is created and is inactive + # analyst approves DomainApplication + # test: Domain is activated + pass + + def test_application_rejection(self): + # DomainApplication is created + # test: Domain is created and is inactive + # analyst rejects DomainApplication + # test: Domain remains inactive + pass + + def test_application_deleted_before_approval(self): + # DomainApplication is created + # test: Domain is created and is inactive + # admin deletes DomainApplication + # test: Domain is deleted; Hosts, HostIps and Nameservers are deleted + pass + + def test_application_deleted_following_approval(self): + # DomainApplication is created + # test: Domain is created and is inactive + # analyst approves DomainApplication + # admin deletes DomainApplication + # test: DomainApplication foreign key field on Domain is set to null + pass + + def test_application_approval_with_conflicting_name(self): + # DomainApplication #1 is created + # test: Domain #1 is created and is inactive + # analyst approves DomainApplication #1 + # test: Domain #1 is activated + # DomainApplication #2 is created, with the same domain name string + # test: Domain #2 is created and is inactive + # analyst approves DomainApplication #2 + # test: error is raised + # test: DomainApplication #1 remains approved + # test: Domain #1 remains active + # test: DomainApplication #2 remains in investigating + # test: Domain #2 remains inactive + pass + + def test_application_approval_with_network_errors(self): + # TODO: scenario wherein application is approved, + # but attempts to contact the registry to activate the domain fail + pass