mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-03 09:43:33 +02:00
Merge pull request #1046 from cisagov/rjm/851-statuses-getter
Issue 851: Domain statuses getter
This commit is contained in:
commit
d92f289556
3 changed files with 125 additions and 37 deletions
|
@ -332,24 +332,23 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
@Cache
|
@Cache
|
||||||
def statuses(self) -> list[str]:
|
def statuses(self) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Get or set the domain `status` elements from the registry.
|
Get the domain `status` elements from the registry.
|
||||||
|
|
||||||
A domain's status indicates various properties. See Domain.Status.
|
A domain's status indicates various properties. See Domain.Status.
|
||||||
"""
|
"""
|
||||||
# implementation note: the Status object from EPP stores the string in
|
try:
|
||||||
# a dataclass property `state`, not to be confused with the `state` field here
|
return self._get_property("statuses")
|
||||||
if "statuses" not in self._cache:
|
except KeyError:
|
||||||
self._fetch_cache()
|
logger.error("Can't retrieve status from domain info")
|
||||||
if "statuses" not in self._cache:
|
return []
|
||||||
raise Exception("Can't retreive status from domain info")
|
|
||||||
else:
|
|
||||||
return self._cache["statuses"]
|
|
||||||
|
|
||||||
@statuses.setter # type: ignore
|
@statuses.setter # type: ignore
|
||||||
def statuses(self, statuses: list[str]):
|
def statuses(self, statuses: list[str]):
|
||||||
# TODO: there are a long list of rules in the RFC about which statuses
|
"""
|
||||||
# can be combined; check that here and raise errors for invalid combinations -
|
We will not implement this. Statuses are set by the registry
|
||||||
# some statuses cannot be set by the client at all
|
when we run delete and client hold, and these are the only statuses
|
||||||
|
we will be triggering.
|
||||||
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@Cache
|
@Cache
|
||||||
|
|
|
@ -547,17 +547,29 @@ class MockEppLib(TestCase):
|
||||||
class fakedEppObject(object):
|
class fakedEppObject(object):
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
def __init__(self, auth_info=..., cr_date=..., contacts=..., hosts=...):
|
def __init__(
|
||||||
|
self,
|
||||||
|
auth_info=...,
|
||||||
|
cr_date=...,
|
||||||
|
contacts=...,
|
||||||
|
hosts=...,
|
||||||
|
statuses=...,
|
||||||
|
):
|
||||||
self.auth_info = auth_info
|
self.auth_info = auth_info
|
||||||
self.cr_date = cr_date
|
self.cr_date = cr_date
|
||||||
self.contacts = contacts
|
self.contacts = contacts
|
||||||
self.hosts = hosts
|
self.hosts = hosts
|
||||||
|
self.statuses = statuses
|
||||||
|
|
||||||
mockDataInfoDomain = fakedEppObject(
|
mockDataInfoDomain = fakedEppObject(
|
||||||
"fakepw",
|
"fakepw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
||||||
contacts=[common.DomainContact(contact="123", type="security")],
|
contacts=[common.DomainContact(contact="123", type="security")],
|
||||||
hosts=["fake.host.com"],
|
hosts=["fake.host.com"],
|
||||||
|
statuses=[
|
||||||
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
||||||
|
common.Status(state="inactive", description="", lang="en"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
infoDomainNoContact = fakedEppObject(
|
infoDomainNoContact = fakedEppObject(
|
||||||
"security",
|
"security",
|
||||||
|
|
|
@ -34,6 +34,8 @@ class TestDomainCache(MockEppLib):
|
||||||
# (see InfoDomainResult)
|
# (see InfoDomainResult)
|
||||||
self.assertEquals(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
|
self.assertEquals(domain._cache["auth_info"], self.mockDataInfoDomain.auth_info)
|
||||||
self.assertEquals(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
|
self.assertEquals(domain._cache["cr_date"], self.mockDataInfoDomain.cr_date)
|
||||||
|
status_list = [status.state for status in self.mockDataInfoDomain.statuses]
|
||||||
|
self.assertEquals(domain._cache["statuses"], status_list)
|
||||||
self.assertFalse("avail" in domain._cache.keys())
|
self.assertFalse("avail" in domain._cache.keys())
|
||||||
|
|
||||||
# using a setter should clear the cache
|
# using a setter should clear the cache
|
||||||
|
@ -49,7 +51,8 @@ class TestDomainCache(MockEppLib):
|
||||||
),
|
),
|
||||||
call(commands.InfoContact(id="123", auth_info=None), cleaned=True),
|
call(commands.InfoContact(id="123", auth_info=None), cleaned=True),
|
||||||
call(commands.InfoHost(name="fake.host.com"), cleaned=True),
|
call(commands.InfoHost(name="fake.host.com"), cleaned=True),
|
||||||
]
|
],
|
||||||
|
any_order=False, # Ensure calls are in the specified order
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cache_used_when_avail(self):
|
def test_cache_used_when_avail(self):
|
||||||
|
@ -106,16 +109,14 @@ class TestDomainCache(MockEppLib):
|
||||||
domain._get_property("hosts")
|
domain._get_property("hosts")
|
||||||
self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
|
self.assertEqual(domain._cache["hosts"], [expectedHostsDict])
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
Domain.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
class TestDomainCreation(TestCase):
|
|
||||||
|
class TestDomainCreation(MockEppLib):
|
||||||
"""Rule: An approved domain application must result in a domain"""
|
"""Rule: An approved domain application must result in a domain"""
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Background:
|
|
||||||
Given that a valid domain application exists
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_approved_application_creates_domain_locally(self):
|
def test_approved_application_creates_domain_locally(self):
|
||||||
"""
|
"""
|
||||||
Scenario: Analyst approves a domain application
|
Scenario: Analyst approves a domain application
|
||||||
|
@ -123,8 +124,6 @@ class TestDomainCreation(TestCase):
|
||||||
Then a Domain exists in the database with the same `name`
|
Then a Domain exists in the database with the same `name`
|
||||||
But a domain object does not exist in the registry
|
But a domain object does not exist in the registry
|
||||||
"""
|
"""
|
||||||
patcher = patch("registrar.models.domain.Domain._get_or_create_domain")
|
|
||||||
mocked_domain_creation = patcher.start()
|
|
||||||
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
||||||
user, _ = User.objects.get_or_create()
|
user, _ = User.objects.get_or_create()
|
||||||
application = DomainApplication.objects.create(
|
application = DomainApplication.objects.create(
|
||||||
|
@ -137,19 +136,46 @@ class TestDomainCreation(TestCase):
|
||||||
# should hav information present for this domain
|
# should hav information present for this domain
|
||||||
domain = Domain.objects.get(name="igorville.gov")
|
domain = Domain.objects.get(name="igorville.gov")
|
||||||
self.assertTrue(domain)
|
self.assertTrue(domain)
|
||||||
mocked_domain_creation.assert_not_called()
|
self.mockedSendFunction.assert_not_called()
|
||||||
|
|
||||||
@skip("not implemented yet")
|
|
||||||
def test_accessing_domain_properties_creates_domain_in_registry(self):
|
def test_accessing_domain_properties_creates_domain_in_registry(self):
|
||||||
"""
|
"""
|
||||||
Scenario: A registrant checks the status of a newly approved domain
|
Scenario: A registrant checks the status of a newly approved domain
|
||||||
Given that no domain object exists in the registry
|
Given that no domain object exists in the registry
|
||||||
When a property is accessed
|
When a property is accessed
|
||||||
Then Domain sends `commands.CreateDomain` to the registry
|
Then Domain sends `commands.CreateDomain` to the registry
|
||||||
And `domain.state` is set to `CREATED`
|
And `domain.state` is set to `UNKNOWN`
|
||||||
And `domain.is_active()` returns False
|
And `domain.is_active()` returns False
|
||||||
"""
|
"""
|
||||||
raise
|
domain = Domain.objects.create(name="beef-tongue.gov")
|
||||||
|
# trigger getter
|
||||||
|
_ = domain.statuses
|
||||||
|
|
||||||
|
# contacts = PublicContact.objects.filter(domain=domain,
|
||||||
|
# type=PublicContact.ContactTypeChoices.REGISTRANT).get()
|
||||||
|
|
||||||
|
# Called in _fetch_cache
|
||||||
|
self.mockedSendFunction.assert_has_calls(
|
||||||
|
[
|
||||||
|
# TODO: due to complexity of the test, will return to it in
|
||||||
|
# a future ticket
|
||||||
|
# call(
|
||||||
|
# commands.CreateDomain(name="beef-tongue.gov",
|
||||||
|
# id=contact.registry_id, auth_info=None),
|
||||||
|
# cleaned=True,
|
||||||
|
# ),
|
||||||
|
call(
|
||||||
|
commands.InfoDomain(name="beef-tongue.gov", auth_info=None),
|
||||||
|
cleaned=True,
|
||||||
|
),
|
||||||
|
call(commands.InfoContact(id="123", auth_info=None), cleaned=True),
|
||||||
|
call(commands.InfoHost(name="fake.host.com"), cleaned=True),
|
||||||
|
],
|
||||||
|
any_order=False, # Ensure calls are in the specified order
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(domain.state, Domain.State.UNKNOWN)
|
||||||
|
self.assertEqual(domain.is_active(), False)
|
||||||
|
|
||||||
@skip("assertion broken with mock addition")
|
@skip("assertion broken with mock addition")
|
||||||
def test_empty_domain_creation(self):
|
def test_empty_domain_creation(self):
|
||||||
|
@ -168,20 +194,71 @@ class TestDomainCreation(TestCase):
|
||||||
with self.assertRaisesRegex(IntegrityError, "name"):
|
with self.assertRaisesRegex(IntegrityError, "name"):
|
||||||
Domain.objects.create(name="igorville.gov")
|
Domain.objects.create(name="igorville.gov")
|
||||||
|
|
||||||
@skip("cannot activate a domain without mock registry")
|
|
||||||
def test_get_status(self):
|
|
||||||
"""Returns proper status based on `state`."""
|
|
||||||
domain = Domain.objects.create(name="igorville.gov")
|
|
||||||
domain.save()
|
|
||||||
self.assertEqual(None, domain.status)
|
|
||||||
domain.activate()
|
|
||||||
domain.save()
|
|
||||||
self.assertIn("ok", domain.status)
|
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
DomainInformation.objects.all().delete()
|
DomainInformation.objects.all().delete()
|
||||||
DomainApplication.objects.all().delete()
|
DomainApplication.objects.all().delete()
|
||||||
Domain.objects.all().delete()
|
Domain.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
class TestDomainStatuses(MockEppLib):
|
||||||
|
"""Domain statuses are set by the registry"""
|
||||||
|
|
||||||
|
def test_get_status(self):
|
||||||
|
"""Domain 'statuses' getter returns statuses by calling epp"""
|
||||||
|
domain, _ = Domain.objects.get_or_create(name="chicken-liver.gov")
|
||||||
|
# trigger getter
|
||||||
|
_ = domain.statuses
|
||||||
|
status_list = [status.state for status in self.mockDataInfoDomain.statuses]
|
||||||
|
self.assertEquals(domain._cache["statuses"], status_list)
|
||||||
|
|
||||||
|
# Called in _fetch_cache
|
||||||
|
self.mockedSendFunction.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(
|
||||||
|
commands.InfoDomain(name="chicken-liver.gov", auth_info=None),
|
||||||
|
cleaned=True,
|
||||||
|
),
|
||||||
|
call(commands.InfoContact(id="123", auth_info=None), cleaned=True),
|
||||||
|
call(commands.InfoHost(name="fake.host.com"), cleaned=True),
|
||||||
|
],
|
||||||
|
any_order=False, # Ensure calls are in the specified order
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_status_returns_empty_list_when_value_error(self):
|
||||||
|
"""Domain 'statuses' getter returns an empty list
|
||||||
|
when value error"""
|
||||||
|
domain, _ = Domain.objects.get_or_create(name="pig-knuckles.gov")
|
||||||
|
|
||||||
|
def side_effect(self):
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
|
patcher = patch("registrar.models.domain.Domain._get_property")
|
||||||
|
mocked_get = patcher.start()
|
||||||
|
mocked_get.side_effect = side_effect
|
||||||
|
|
||||||
|
# trigger getter
|
||||||
|
_ = domain.statuses
|
||||||
|
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
_ = domain._cache["statuses"]
|
||||||
|
self.assertEquals(_, [])
|
||||||
|
|
||||||
|
patcher.stop()
|
||||||
|
|
||||||
|
@skip("not implemented yet")
|
||||||
|
def test_place_client_hold_sets_status(self):
|
||||||
|
"""Domain 'place_client_hold' method causes the registry to change statuses"""
|
||||||
|
raise
|
||||||
|
|
||||||
|
@skip("not implemented yet")
|
||||||
|
def test_revert_client_hold_sets_status(self):
|
||||||
|
"""Domain 'revert_client_hold' method causes the registry to change statuses"""
|
||||||
|
raise
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
Domain.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
class TestRegistrantContacts(MockEppLib):
|
class TestRegistrantContacts(MockEppLib):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue