mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-01 02:03:56 +02:00
Merge branch 'main' into za/1411-make-statuses-more-meaningful
This commit is contained in:
commit
7c05762293
24 changed files with 6682 additions and 6776 deletions
|
@ -145,7 +145,7 @@ You can change the logging verbosity, if needed. Do a web search for "django log
|
||||||
|
|
||||||
## Mock data
|
## Mock data
|
||||||
|
|
||||||
There is a `post_migrate` signal in [signals.py](../../src/registrar/signals.py) that will load the fixtures from [fixtures_user.py](../../src/registrar/fixtures_users.py) and [fixtures_applications.py](../../src/registrar/fixtures_applications.py), giving you some test data to play with while developing.
|
[load.py](../../src/registrar/management/commands/load.py) called from docker-compose (locally) and reset-db.yml (upper) loads the fixtures from [fixtures_user.py](../../src/registrar/fixtures_users.py) and [fixtures_applications.py](../../src/registrar/fixtures_applications.py), giving you some test data to play with while developing.
|
||||||
|
|
||||||
See the [database-access README](./database-access.md) for information on how to pull data to update these fixtures.
|
See the [database-access README](./database-access.md) for information on how to pull data to update these fixtures.
|
||||||
|
|
||||||
|
|
|
@ -35,155 +35,155 @@ class ViewsTest(TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_openid_sets_next(self, mock_client):
|
def test_openid_sets_next(self, mock_client):
|
||||||
# setup
|
with less_console_noise():
|
||||||
callback_url = reverse("openid_login_callback")
|
# setup
|
||||||
# mock
|
callback_url = reverse("openid_login_callback")
|
||||||
mock_client.create_authn_request.side_effect = self.say_hi
|
# mock
|
||||||
mock_client.get_default_acr_value.side_effect = self.create_acr
|
mock_client.create_authn_request.side_effect = self.say_hi
|
||||||
# test
|
mock_client.get_default_acr_value.side_effect = self.create_acr
|
||||||
response = self.client.get(reverse("login"), {"next": callback_url})
|
# test
|
||||||
# assert
|
response = self.client.get(reverse("login"), {"next": callback_url})
|
||||||
session = mock_client.create_authn_request.call_args[0][0]
|
# assert
|
||||||
self.assertEqual(session["next"], callback_url)
|
session = mock_client.create_authn_request.call_args[0][0]
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(session["next"], callback_url)
|
||||||
self.assertContains(response, "Hi")
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertContains(response, "Hi")
|
||||||
|
|
||||||
def test_openid_raises(self, mock_client):
|
def test_openid_raises(self, mock_client):
|
||||||
# mock
|
|
||||||
mock_client.create_authn_request.side_effect = Exception("Test")
|
|
||||||
# test
|
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
|
# mock
|
||||||
|
mock_client.create_authn_request.side_effect = Exception("Test")
|
||||||
|
# test
|
||||||
response = self.client.get(reverse("login"))
|
response = self.client.get(reverse("login"))
|
||||||
# assert
|
# assert
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
self.assertTemplateUsed(response, "500.html")
|
self.assertTemplateUsed(response, "500.html")
|
||||||
self.assertIn("Server error", response.content.decode("utf-8"))
|
self.assertIn("Server error", response.content.decode("utf-8"))
|
||||||
|
|
||||||
def test_callback_with_no_session_state(self, mock_client):
|
def test_callback_with_no_session_state(self, mock_client):
|
||||||
"""If the local session is None (ie the server restarted while user was logged out),
|
"""If the local session is None (ie the server restarted while user was logged out),
|
||||||
we do not throw an exception. Rather, we attempt to login again."""
|
we do not throw an exception. Rather, we attempt to login again."""
|
||||||
# mock
|
|
||||||
mock_client.get_default_acr_value.side_effect = self.create_acr
|
|
||||||
mock_client.callback.side_effect = NoStateDefined()
|
|
||||||
# test
|
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
|
# mock
|
||||||
|
mock_client.get_default_acr_value.side_effect = self.create_acr
|
||||||
|
mock_client.callback.side_effect = NoStateDefined()
|
||||||
|
# test
|
||||||
response = self.client.get(reverse("openid_login_callback"))
|
response = self.client.get(reverse("openid_login_callback"))
|
||||||
# assert
|
# assert
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(response.url, "/")
|
self.assertEqual(response.url, "/")
|
||||||
|
|
||||||
def test_login_callback_reads_next(self, mock_client):
|
def test_login_callback_reads_next(self, mock_client):
|
||||||
# setup
|
with less_console_noise():
|
||||||
session = self.client.session
|
# setup
|
||||||
session["next"] = reverse("logout")
|
session = self.client.session
|
||||||
session.save()
|
session["next"] = reverse("logout")
|
||||||
# mock
|
session.save()
|
||||||
mock_client.callback.side_effect = self.user_info
|
# mock
|
||||||
# test
|
mock_client.callback.side_effect = self.user_info
|
||||||
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
# test
|
||||||
response = self.client.get(reverse("openid_login_callback"))
|
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
||||||
# assert
|
response = self.client.get(reverse("openid_login_callback"))
|
||||||
self.assertEqual(response.status_code, 302)
|
# assert
|
||||||
self.assertEqual(response.url, reverse("logout"))
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, reverse("logout"))
|
||||||
|
|
||||||
def test_login_callback_no_step_up_auth(self, mock_client):
|
def test_login_callback_no_step_up_auth(self, mock_client):
|
||||||
"""Walk through login_callback when requires_step_up_auth returns False
|
"""Walk through login_callback when requires_step_up_auth returns False
|
||||||
and assert that we have a redirect to /"""
|
and assert that we have a redirect to /"""
|
||||||
# setup
|
with less_console_noise():
|
||||||
session = self.client.session
|
# setup
|
||||||
session.save()
|
session = self.client.session
|
||||||
# mock
|
session.save()
|
||||||
mock_client.callback.side_effect = self.user_info
|
# mock
|
||||||
# test
|
mock_client.callback.side_effect = self.user_info
|
||||||
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
# test
|
||||||
response = self.client.get(reverse("openid_login_callback"))
|
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
||||||
# assert
|
response = self.client.get(reverse("openid_login_callback"))
|
||||||
self.assertEqual(response.status_code, 302)
|
# assert
|
||||||
self.assertEqual(response.url, "/")
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, "/")
|
||||||
|
|
||||||
def test_requires_step_up_auth(self, mock_client):
|
def test_requires_step_up_auth(self, mock_client):
|
||||||
"""Invoke login_callback passing it a request when requires_step_up_auth returns True
|
"""Invoke login_callback passing it a request when requires_step_up_auth returns True
|
||||||
and assert that session is updated and create_authn_request (mock) is called."""
|
and assert that session is updated and create_authn_request (mock) is called."""
|
||||||
# Configure the mock to return an expected value for get_step_up_acr_value
|
with less_console_noise():
|
||||||
mock_client.return_value.get_step_up_acr_value.return_value = "step_up_acr_value"
|
# Configure the mock to return an expected value for get_step_up_acr_value
|
||||||
|
mock_client.return_value.get_step_up_acr_value.return_value = "step_up_acr_value"
|
||||||
# Create a mock request
|
# Create a mock request
|
||||||
request = self.factory.get("/some-url")
|
request = self.factory.get("/some-url")
|
||||||
request.session = {"acr_value": ""}
|
request.session = {"acr_value": ""}
|
||||||
|
# Ensure that the CLIENT instance used in login_callback is the mock
|
||||||
# Ensure that the CLIENT instance used in login_callback is the mock
|
# patch requires_step_up_auth to return True
|
||||||
# patch requires_step_up_auth to return True
|
with patch("djangooidc.views.requires_step_up_auth", return_value=True), patch(
|
||||||
with patch("djangooidc.views.requires_step_up_auth", return_value=True), patch(
|
"djangooidc.views.CLIENT.create_authn_request", return_value=MagicMock()
|
||||||
"djangooidc.views.CLIENT.create_authn_request", return_value=MagicMock()
|
) as mock_create_authn_request:
|
||||||
) as mock_create_authn_request:
|
login_callback(request)
|
||||||
login_callback(request)
|
# create_authn_request only gets called when requires_step_up_auth is True
|
||||||
|
# and it changes this acr_value in request.session
|
||||||
# create_authn_request only gets called when requires_step_up_auth is True
|
# Assert that acr_value is no longer empty string
|
||||||
# and it changes this acr_value in request.session
|
self.assertNotEqual(request.session["acr_value"], "")
|
||||||
|
# And create_authn_request was called again
|
||||||
# Assert that acr_value is no longer empty string
|
mock_create_authn_request.assert_called_once()
|
||||||
self.assertNotEqual(request.session["acr_value"], "")
|
|
||||||
# And create_authn_request was called again
|
|
||||||
mock_create_authn_request.assert_called_once()
|
|
||||||
|
|
||||||
def test_does_not_requires_step_up_auth(self, mock_client):
|
def test_does_not_requires_step_up_auth(self, mock_client):
|
||||||
"""Invoke login_callback passing it a request when requires_step_up_auth returns False
|
"""Invoke login_callback passing it a request when requires_step_up_auth returns False
|
||||||
and assert that session is not updated and create_authn_request (mock) is not called.
|
and assert that session is not updated and create_authn_request (mock) is not called.
|
||||||
|
|
||||||
Possibly redundant with test_login_callback_requires_step_up_auth"""
|
Possibly redundant with test_login_callback_requires_step_up_auth"""
|
||||||
# Create a mock request
|
with less_console_noise():
|
||||||
request = self.factory.get("/some-url")
|
# Create a mock request
|
||||||
request.session = {"acr_value": ""}
|
request = self.factory.get("/some-url")
|
||||||
|
request.session = {"acr_value": ""}
|
||||||
# Ensure that the CLIENT instance used in login_callback is the mock
|
# Ensure that the CLIENT instance used in login_callback is the mock
|
||||||
# patch requires_step_up_auth to return False
|
# patch requires_step_up_auth to return False
|
||||||
with patch("djangooidc.views.requires_step_up_auth", return_value=False), patch(
|
with patch("djangooidc.views.requires_step_up_auth", return_value=False), patch(
|
||||||
"djangooidc.views.CLIENT.create_authn_request", return_value=MagicMock()
|
"djangooidc.views.CLIENT.create_authn_request", return_value=MagicMock()
|
||||||
) as mock_create_authn_request:
|
) as mock_create_authn_request:
|
||||||
login_callback(request)
|
login_callback(request)
|
||||||
|
# create_authn_request only gets called when requires_step_up_auth is True
|
||||||
# create_authn_request only gets called when requires_step_up_auth is True
|
# and it changes this acr_value in request.session
|
||||||
# and it changes this acr_value in request.session
|
# Assert that acr_value is NOT updated by testing that it is still an empty string
|
||||||
|
self.assertEqual(request.session["acr_value"], "")
|
||||||
# Assert that acr_value is NOT updated by testing that it is still an empty string
|
# Assert create_authn_request was not called
|
||||||
self.assertEqual(request.session["acr_value"], "")
|
mock_create_authn_request.assert_not_called()
|
||||||
# Assert create_authn_request was not called
|
|
||||||
mock_create_authn_request.assert_not_called()
|
|
||||||
|
|
||||||
@patch("djangooidc.views.authenticate")
|
@patch("djangooidc.views.authenticate")
|
||||||
def test_login_callback_raises(self, mock_auth, mock_client):
|
def test_login_callback_raises(self, mock_auth, mock_client):
|
||||||
# mock
|
with less_console_noise():
|
||||||
mock_client.callback.side_effect = self.user_info
|
# mock
|
||||||
mock_auth.return_value = None
|
mock_client.callback.side_effect = self.user_info
|
||||||
# test
|
mock_auth.return_value = None
|
||||||
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
# test
|
||||||
response = self.client.get(reverse("openid_login_callback"))
|
with patch("djangooidc.views.requires_step_up_auth", return_value=False), less_console_noise():
|
||||||
# assert
|
response = self.client.get(reverse("openid_login_callback"))
|
||||||
self.assertEqual(response.status_code, 401)
|
# assert
|
||||||
self.assertTemplateUsed(response, "401.html")
|
self.assertEqual(response.status_code, 401)
|
||||||
self.assertIn("Unauthorized", response.content.decode("utf-8"))
|
self.assertTemplateUsed(response, "401.html")
|
||||||
|
self.assertIn("Unauthorized", response.content.decode("utf-8"))
|
||||||
|
|
||||||
def test_logout_redirect_url(self, mock_client):
|
def test_logout_redirect_url(self, mock_client):
|
||||||
# setup
|
|
||||||
session = self.client.session
|
|
||||||
session["state"] = "TEST" # nosec B105
|
|
||||||
session.save()
|
|
||||||
# mock
|
|
||||||
mock_client.callback.side_effect = self.user_info
|
|
||||||
mock_client.registration_response = {"post_logout_redirect_uris": ["http://example.com/back"]}
|
|
||||||
mock_client.provider_info = {"end_session_endpoint": "http://example.com/log_me_out"}
|
|
||||||
mock_client.client_id = "TEST"
|
|
||||||
# test
|
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
response = self.client.get(reverse("logout"))
|
# setup
|
||||||
# assert
|
session = self.client.session
|
||||||
expected = (
|
session["state"] = "TEST" # nosec B105
|
||||||
"http://example.com/log_me_out?client_id=TEST&state"
|
session.save()
|
||||||
"=TEST&post_logout_redirect_uri=http%3A%2F%2Fexample.com%2Fback"
|
# mock
|
||||||
)
|
mock_client.callback.side_effect = self.user_info
|
||||||
actual = response.url
|
mock_client.registration_response = {"post_logout_redirect_uris": ["http://example.com/back"]}
|
||||||
self.assertEqual(response.status_code, 302)
|
mock_client.provider_info = {"end_session_endpoint": "http://example.com/log_me_out"}
|
||||||
self.assertEqual(actual, expected)
|
mock_client.client_id = "TEST"
|
||||||
|
# test
|
||||||
|
with less_console_noise():
|
||||||
|
response = self.client.get(reverse("logout"))
|
||||||
|
# assert
|
||||||
|
expected = (
|
||||||
|
"http://example.com/log_me_out?client_id=TEST&state"
|
||||||
|
"=TEST&post_logout_redirect_uri=http%3A%2F%2Fexample.com%2Fback"
|
||||||
|
)
|
||||||
|
actual = response.url
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
@patch("djangooidc.views.auth_logout")
|
@patch("djangooidc.views.auth_logout")
|
||||||
def test_logout_always_logs_out(self, mock_logout, _):
|
def test_logout_always_logs_out(self, mock_logout, _):
|
||||||
|
@ -194,12 +194,13 @@ class ViewsTest(TestCase):
|
||||||
self.assertTrue(mock_logout.called)
|
self.assertTrue(mock_logout.called)
|
||||||
|
|
||||||
def test_logout_callback_redirects(self, _):
|
def test_logout_callback_redirects(self, _):
|
||||||
# setup
|
with less_console_noise():
|
||||||
session = self.client.session
|
# setup
|
||||||
session["next"] = reverse("logout")
|
session = self.client.session
|
||||||
session.save()
|
session["next"] = reverse("logout")
|
||||||
# test
|
session.save()
|
||||||
response = self.client.get(reverse("openid_logout_callback"))
|
# test
|
||||||
# assert
|
response = self.client.get(reverse("openid_logout_callback"))
|
||||||
self.assertEqual(response.status_code, 302)
|
# assert
|
||||||
self.assertEqual(response.url, reverse("logout"))
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, reverse("logout"))
|
||||||
|
|
51
src/epplibwrapper/tests/common.py
Normal file
51
src/epplibwrapper/tests/common.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
|
def get_handlers():
|
||||||
|
"""Obtain pointers to all StreamHandlers."""
|
||||||
|
handlers = {}
|
||||||
|
|
||||||
|
rootlogger = logging.getLogger()
|
||||||
|
for h in rootlogger.handlers:
|
||||||
|
if isinstance(h, logging.StreamHandler):
|
||||||
|
handlers[h.name] = h
|
||||||
|
|
||||||
|
for logger in logging.Logger.manager.loggerDict.values():
|
||||||
|
if not isinstance(logger, logging.PlaceHolder):
|
||||||
|
for h in logger.handlers:
|
||||||
|
if isinstance(h, logging.StreamHandler):
|
||||||
|
handlers[h.name] = h
|
||||||
|
|
||||||
|
return handlers
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def less_console_noise():
|
||||||
|
"""
|
||||||
|
Context manager to use in tests to silence console logging.
|
||||||
|
|
||||||
|
This is helpful on tests which trigger console messages
|
||||||
|
(such as errors) which are normal and expected.
|
||||||
|
|
||||||
|
It can easily be removed to debug a failing test.
|
||||||
|
"""
|
||||||
|
restore = {}
|
||||||
|
handlers = get_handlers()
|
||||||
|
devnull = open(os.devnull, "w")
|
||||||
|
|
||||||
|
# redirect all the streams
|
||||||
|
for handler in handlers.values():
|
||||||
|
prior = handler.setStream(devnull)
|
||||||
|
restore[handler.name] = prior
|
||||||
|
try:
|
||||||
|
# run the test
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
# restore the streams
|
||||||
|
for handler in handlers.values():
|
||||||
|
handler.setStream(restore[handler.name])
|
||||||
|
# close the file we opened
|
||||||
|
devnull.close()
|
|
@ -9,7 +9,7 @@ from epplibwrapper.socket import Socket
|
||||||
from epplibwrapper.utility.pool import EPPConnectionPool
|
from epplibwrapper.utility.pool import EPPConnectionPool
|
||||||
from registrar.models.domain import registry
|
from registrar.models.domain import registry
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
|
from .common import less_console_noise
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -135,23 +135,26 @@ class TestConnectionPool(TestCase):
|
||||||
stack.enter_context(patch.object(EPPConnectionPool, "kill_all_connections", do_nothing))
|
stack.enter_context(patch.object(EPPConnectionPool, "kill_all_connections", do_nothing))
|
||||||
stack.enter_context(patch.object(SocketTransport, "send", self.fake_send))
|
stack.enter_context(patch.object(SocketTransport, "send", self.fake_send))
|
||||||
stack.enter_context(patch.object(SocketTransport, "receive", fake_receive))
|
stack.enter_context(patch.object(SocketTransport, "receive", fake_receive))
|
||||||
# Restart the connection pool
|
with less_console_noise():
|
||||||
registry.start_connection_pool()
|
# Restart the connection pool
|
||||||
# Pool should be running, and be the right size
|
registry.start_connection_pool()
|
||||||
self.assertEqual(registry.pool_status.connection_success, True)
|
# Pool should be running, and be the right size
|
||||||
self.assertEqual(registry.pool_status.pool_running, True)
|
self.assertEqual(registry.pool_status.connection_success, True)
|
||||||
|
self.assertEqual(registry.pool_status.pool_running, True)
|
||||||
|
|
||||||
# Send a command
|
# Send a command
|
||||||
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
||||||
|
|
||||||
# Should this ever fail, it either means that the schema has changed,
|
# Should this ever fail, it either means that the schema has changed,
|
||||||
# or the pool is broken.
|
# or the pool is broken.
|
||||||
# If the schema has changed: Update the associated infoDomain.xml file
|
# If the schema has changed: Update the associated infoDomain.xml file
|
||||||
self.assertEqual(result.__dict__, expected_result)
|
self.assertEqual(result.__dict__, expected_result)
|
||||||
|
|
||||||
# The number of open pools should match the number of requested ones.
|
# The number of open pools should match the number of requested ones.
|
||||||
# If it is 0, then they failed to open
|
# If it is 0, then they failed to open
|
||||||
self.assertEqual(len(registry._pool.conn), self.pool_options["size"])
|
self.assertEqual(len(registry._pool.conn), self.pool_options["size"])
|
||||||
|
# Kill the connection pool
|
||||||
|
registry.kill_pool()
|
||||||
|
|
||||||
@patch.object(EPPLibWrapper, "_test_registry_connection_success", patch_success)
|
@patch.object(EPPLibWrapper, "_test_registry_connection_success", patch_success)
|
||||||
def test_pool_restarts_on_send(self):
|
def test_pool_restarts_on_send(self):
|
||||||
|
@ -198,35 +201,43 @@ class TestConnectionPool(TestCase):
|
||||||
xml = (location).read_bytes()
|
xml = (location).read_bytes()
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
def do_nothing(command):
|
||||||
|
pass
|
||||||
|
|
||||||
# Mock what happens inside the "with"
|
# Mock what happens inside the "with"
|
||||||
with ExitStack() as stack:
|
with ExitStack() as stack:
|
||||||
stack.enter_context(patch.object(EPPConnectionPool, "_create_socket", self.fake_socket))
|
stack.enter_context(patch.object(EPPConnectionPool, "_create_socket", self.fake_socket))
|
||||||
stack.enter_context(patch.object(Socket, "connect", self.fake_client))
|
stack.enter_context(patch.object(Socket, "connect", self.fake_client))
|
||||||
|
stack.enter_context(patch.object(EPPConnectionPool, "kill_all_connections", do_nothing))
|
||||||
stack.enter_context(patch.object(SocketTransport, "send", self.fake_send))
|
stack.enter_context(patch.object(SocketTransport, "send", self.fake_send))
|
||||||
stack.enter_context(patch.object(SocketTransport, "receive", fake_receive))
|
stack.enter_context(patch.object(SocketTransport, "receive", fake_receive))
|
||||||
# Kill the connection pool
|
with less_console_noise():
|
||||||
registry.kill_pool()
|
# Start the connection pool
|
||||||
|
registry.start_connection_pool()
|
||||||
|
# Kill the connection pool
|
||||||
|
registry.kill_pool()
|
||||||
|
|
||||||
self.assertEqual(registry.pool_status.connection_success, False)
|
self.assertEqual(registry.pool_status.pool_running, False)
|
||||||
self.assertEqual(registry.pool_status.pool_running, False)
|
|
||||||
|
|
||||||
# An exception should be raised as end user will be informed
|
# An exception should be raised as end user will be informed
|
||||||
# that they cannot connect to EPP
|
# that they cannot connect to EPP
|
||||||
with self.assertRaises(RegistryError):
|
with self.assertRaises(RegistryError):
|
||||||
expected = "InfoDomain failed to execute due to a connection error."
|
expected = "InfoDomain failed to execute due to a connection error."
|
||||||
|
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
# A subsequent command should be successful, as the pool restarts
|
||||||
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
||||||
self.assertEqual(result, expected)
|
# Should this ever fail, it either means that the schema has changed,
|
||||||
|
# or the pool is broken.
|
||||||
|
# If the schema has changed: Update the associated infoDomain.xml file
|
||||||
|
self.assertEqual(result.__dict__, expected_result)
|
||||||
|
|
||||||
# A subsequent command should be successful, as the pool restarts
|
# The number of open pools should match the number of requested ones.
|
||||||
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
# If it is 0, then they failed to open
|
||||||
# Should this ever fail, it either means that the schema has changed,
|
self.assertEqual(len(registry._pool.conn), self.pool_options["size"])
|
||||||
# or the pool is broken.
|
# Kill the connection pool
|
||||||
# If the schema has changed: Update the associated infoDomain.xml file
|
registry.kill_pool()
|
||||||
self.assertEqual(result.__dict__, expected_result)
|
|
||||||
|
|
||||||
# The number of open pools should match the number of requested ones.
|
|
||||||
# If it is 0, then they failed to open
|
|
||||||
self.assertEqual(len(registry._pool.conn), self.pool_options["size"])
|
|
||||||
|
|
||||||
@patch.object(EPPLibWrapper, "_test_registry_connection_success", patch_success)
|
@patch.object(EPPLibWrapper, "_test_registry_connection_success", patch_success)
|
||||||
def test_raises_connection_error(self):
|
def test_raises_connection_error(self):
|
||||||
|
@ -236,13 +247,16 @@ class TestConnectionPool(TestCase):
|
||||||
with ExitStack() as stack:
|
with ExitStack() as stack:
|
||||||
stack.enter_context(patch.object(EPPConnectionPool, "_create_socket", self.fake_socket))
|
stack.enter_context(patch.object(EPPConnectionPool, "_create_socket", self.fake_socket))
|
||||||
stack.enter_context(patch.object(Socket, "connect", self.fake_client))
|
stack.enter_context(patch.object(Socket, "connect", self.fake_client))
|
||||||
|
with less_console_noise():
|
||||||
|
# Start the connection pool
|
||||||
|
registry.start_connection_pool()
|
||||||
|
|
||||||
# Pool should be running
|
# Pool should be running
|
||||||
self.assertEqual(registry.pool_status.connection_success, True)
|
self.assertEqual(registry.pool_status.connection_success, True)
|
||||||
self.assertEqual(registry.pool_status.pool_running, True)
|
self.assertEqual(registry.pool_status.pool_running, True)
|
||||||
|
|
||||||
# Try to send a command out - should fail
|
# Try to send a command out - should fail
|
||||||
with self.assertRaises(RegistryError):
|
with self.assertRaises(RegistryError):
|
||||||
expected = "InfoDomain failed to execute due to a connection error."
|
expected = "InfoDomain failed to execute due to a connection error."
|
||||||
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
|
@ -85,6 +85,21 @@ class EPPConnectionPool(ConnectionPool):
|
||||||
logger.error(message, exc_info=True)
|
logger.error(message, exc_info=True)
|
||||||
raise PoolError(code=PoolErrorCodes.KEEP_ALIVE_FAILED) from err
|
raise PoolError(code=PoolErrorCodes.KEEP_ALIVE_FAILED) from err
|
||||||
|
|
||||||
|
def _keepalive_periodic(self):
|
||||||
|
"""Overriding _keepalive_periodic from geventconnpool so that PoolErrors
|
||||||
|
are properly handled, as opposed to printing to stdout"""
|
||||||
|
delay = float(self.keepalive) / self.size
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
with self.get() as c:
|
||||||
|
self._keepalive(c)
|
||||||
|
except PoolError as err:
|
||||||
|
logger.error(err.message, exc_info=True)
|
||||||
|
except self.exc_classes:
|
||||||
|
# Nothing to do, the pool will generate a new connection later
|
||||||
|
pass
|
||||||
|
gevent.sleep(delay)
|
||||||
|
|
||||||
def _create_socket(self, client, login) -> Socket:
|
def _create_socket(self, client, login) -> Socket:
|
||||||
"""Creates and returns a socket instance"""
|
"""Creates and returns a socket instance"""
|
||||||
socket = Socket(client, login)
|
socket = Socket(client, login)
|
||||||
|
|
|
@ -677,6 +677,7 @@ class DomainInformationAdmin(ListHeaderAdmin):
|
||||||
"type_of_work",
|
"type_of_work",
|
||||||
"more_organization_information",
|
"more_organization_information",
|
||||||
"domain",
|
"domain",
|
||||||
|
"domain_application",
|
||||||
"submitter",
|
"submitter",
|
||||||
"no_other_contacts_rationale",
|
"no_other_contacts_rationale",
|
||||||
"anything_else",
|
"anything_else",
|
||||||
|
@ -845,6 +846,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
|
||||||
"creator",
|
"creator",
|
||||||
"about_your_organization",
|
"about_your_organization",
|
||||||
"requested_domain",
|
"requested_domain",
|
||||||
|
"approved_domain",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
"purpose",
|
"purpose",
|
||||||
"submitter",
|
"submitter",
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.utils import timezone
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from registrar.models.host import Host
|
from registrar.models.host import Host
|
||||||
from registrar.models.host_ip import HostIP
|
from registrar.models.host_ip import HostIP
|
||||||
|
from registrar.utility.enums import DefaultEmail
|
||||||
|
|
||||||
from registrar.utility.errors import (
|
from registrar.utility.errors import (
|
||||||
ActionNotAllowed,
|
ActionNotAllowed,
|
||||||
|
@ -1437,7 +1438,9 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
is_security = contact.contact_type == contact.ContactTypeChoices.SECURITY
|
is_security = contact.contact_type == contact.ContactTypeChoices.SECURITY
|
||||||
DF = epp.DiscloseField
|
DF = epp.DiscloseField
|
||||||
fields = {DF.EMAIL}
|
fields = {DF.EMAIL}
|
||||||
disclose = is_security and contact.email != PublicContact.get_default_security().email
|
|
||||||
|
hidden_security_emails = [DefaultEmail.PUBLIC_CONTACT_DEFAULT.value, DefaultEmail.LEGACY_DEFAULT.value]
|
||||||
|
disclose = is_security and contact.email not in hidden_security_emails
|
||||||
# Delete after testing on other devices
|
# Delete after testing on other devices
|
||||||
logger.info("Updated domain contact %s to disclose: %s", contact.email, disclose)
|
logger.info("Updated domain contact %s to disclose: %s", contact.email, disclose)
|
||||||
# Will only disclose DF.EMAIL if its not the default
|
# Will only disclose DF.EMAIL if its not the default
|
||||||
|
|
|
@ -4,6 +4,8 @@ from string import ascii_uppercase, ascii_lowercase, digits
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from registrar.utility.enums import DefaultEmail
|
||||||
|
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ class PublicContact(TimeStampedModel):
|
||||||
sp="VA",
|
sp="VA",
|
||||||
pc="20598-0645",
|
pc="20598-0645",
|
||||||
cc="US",
|
cc="US",
|
||||||
email="dotgov@cisa.dhs.gov",
|
email=DefaultEmail.PUBLIC_CONTACT_DEFAULT.value,
|
||||||
voice="+1.8882820870",
|
voice="+1.8882820870",
|
||||||
pw="thisisnotapassword",
|
pw="thisisnotapassword",
|
||||||
)
|
)
|
||||||
|
@ -104,7 +106,7 @@ class PublicContact(TimeStampedModel):
|
||||||
sp="VA",
|
sp="VA",
|
||||||
pc="22201",
|
pc="22201",
|
||||||
cc="US",
|
cc="US",
|
||||||
email="dotgov@cisa.dhs.gov",
|
email=DefaultEmail.PUBLIC_CONTACT_DEFAULT.value,
|
||||||
voice="+1.8882820870",
|
voice="+1.8882820870",
|
||||||
pw="thisisnotapassword",
|
pw="thisisnotapassword",
|
||||||
)
|
)
|
||||||
|
@ -121,7 +123,7 @@ class PublicContact(TimeStampedModel):
|
||||||
sp="VA",
|
sp="VA",
|
||||||
pc="22201",
|
pc="22201",
|
||||||
cc="US",
|
cc="US",
|
||||||
email="dotgov@cisa.dhs.gov",
|
email=DefaultEmail.PUBLIC_CONTACT_DEFAULT.value,
|
||||||
voice="+1.8882820870",
|
voice="+1.8882820870",
|
||||||
pw="thisisnotapassword",
|
pw="thisisnotapassword",
|
||||||
)
|
)
|
||||||
|
@ -138,7 +140,7 @@ class PublicContact(TimeStampedModel):
|
||||||
sp="VA",
|
sp="VA",
|
||||||
pc="22201",
|
pc="22201",
|
||||||
cc="US",
|
cc="US",
|
||||||
email="dotgov@cisa.dhs.gov",
|
email=DefaultEmail.PUBLIC_CONTACT_DEFAULT.value,
|
||||||
voice="+1.8882820870",
|
voice="+1.8882820870",
|
||||||
pw="thisisnotapassword",
|
pw="thisisnotapassword",
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>Names that <em>uniquely apply to your organization</em> are likely to be approved over names that could also apply to other organizations. In most instances, this requires including your state’s two-letter abbreviation.</p>
|
<p>Names that <em>uniquely apply to your organization</em> are likely to be approved over names that could also apply to other organizations.
|
||||||
|
{% if not is_federal %}In most instances, this requires including your state’s two-letter abbreviation.{% endif %}</p>
|
||||||
|
|
||||||
<p>Requests for your organization’s initials or an abbreviated name might not be approved, but we encourage you to request the name you want.</p>
|
<p>Requests for your organization’s initials or an abbreviated name might not be approved, but we encourage you to request the name you want.</p>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static form_helpers url_helpers %}
|
{% load static form_helpers url_helpers %}
|
||||||
|
|
||||||
{% block title %}Request a .gov domain | {{form_titles|get_item:steps.current}} | {% endblock %}
|
{% block title %}{{form_titles|get_item:steps.current}} | Request a .gov | {% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
{% include "includes/summary_item.html" with title='Your contact information' value=request.user.contact contact='true' edit_link=url editable=domain.is_editable %}
|
{% include "includes/summary_item.html" with title='Your contact information' value=request.user.contact contact='true' edit_link=url editable=domain.is_editable %}
|
||||||
|
|
||||||
{% url 'domain-security-email' pk=domain.id as url %}
|
{% url 'domain-security-email' pk=domain.id as url %}
|
||||||
{% if security_email is not None and security_email != default_security_email%}
|
{% if security_email is not None and security_email not in hidden_security_emails%}
|
||||||
{% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=domain.is_editable %}
|
{% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=domain.is_editable %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url editable=domain.is_editable %}
|
{% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url editable=domain.is_editable %}
|
||||||
|
|
|
@ -12,6 +12,7 @@ from typing import List, Dict
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
from django.contrib.sessions.middleware import SessionMiddleware
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model, login
|
from django.contrib.auth import get_user_model, login
|
||||||
|
from django.utils.timezone import make_aware
|
||||||
|
|
||||||
from registrar.models import (
|
from registrar.models import (
|
||||||
Contact,
|
Contact,
|
||||||
|
@ -643,7 +644,7 @@ class MockEppLib(TestCase):
|
||||||
self,
|
self,
|
||||||
id,
|
id,
|
||||||
email,
|
email,
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
pw="thisisnotapassword",
|
pw="thisisnotapassword",
|
||||||
):
|
):
|
||||||
fake = info.InfoContactResultData(
|
fake = info.InfoContactResultData(
|
||||||
|
@ -681,7 +682,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
mockDataInfoDomain = fakedEppObject(
|
mockDataInfoDomain = fakedEppObject(
|
||||||
"fakePw",
|
"fakePw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
|
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
|
||||||
hosts=["fake.host.com"],
|
hosts=["fake.host.com"],
|
||||||
statuses=[
|
statuses=[
|
||||||
|
@ -692,7 +693,7 @@ class MockEppLib(TestCase):
|
||||||
)
|
)
|
||||||
mockDataExtensionDomain = fakedEppObject(
|
mockDataExtensionDomain = fakedEppObject(
|
||||||
"fakePw",
|
"fakePw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
|
contacts=[common.DomainContact(contact="123", type=PublicContact.ContactTypeChoices.SECURITY)],
|
||||||
hosts=["fake.host.com"],
|
hosts=["fake.host.com"],
|
||||||
statuses=[
|
statuses=[
|
||||||
|
@ -706,7 +707,7 @@ class MockEppLib(TestCase):
|
||||||
)
|
)
|
||||||
InfoDomainWithContacts = fakedEppObject(
|
InfoDomainWithContacts = fakedEppObject(
|
||||||
"fakepw",
|
"fakepw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="securityContact",
|
contact="securityContact",
|
||||||
|
@ -731,7 +732,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
InfoDomainWithDefaultSecurityContact = fakedEppObject(
|
InfoDomainWithDefaultSecurityContact = fakedEppObject(
|
||||||
"fakepw",
|
"fakepw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="defaultSec",
|
contact="defaultSec",
|
||||||
|
@ -750,7 +751,7 @@ class MockEppLib(TestCase):
|
||||||
)
|
)
|
||||||
InfoDomainWithVerisignSecurityContact = fakedEppObject(
|
InfoDomainWithVerisignSecurityContact = fakedEppObject(
|
||||||
"fakepw",
|
"fakepw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="defaultVeri",
|
contact="defaultVeri",
|
||||||
|
@ -766,7 +767,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
InfoDomainWithDefaultTechnicalContact = fakedEppObject(
|
InfoDomainWithDefaultTechnicalContact = fakedEppObject(
|
||||||
"fakepw",
|
"fakepw",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="defaultTech",
|
contact="defaultTech",
|
||||||
|
@ -791,14 +792,14 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
infoDomainNoContact = fakedEppObject(
|
infoDomainNoContact = fakedEppObject(
|
||||||
"security",
|
"security",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[],
|
contacts=[],
|
||||||
hosts=["fake.host.com"],
|
hosts=["fake.host.com"],
|
||||||
)
|
)
|
||||||
|
|
||||||
infoDomainThreeHosts = fakedEppObject(
|
infoDomainThreeHosts = fakedEppObject(
|
||||||
"my-nameserver.gov",
|
"my-nameserver.gov",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[],
|
contacts=[],
|
||||||
hosts=[
|
hosts=[
|
||||||
"ns1.my-nameserver-1.com",
|
"ns1.my-nameserver-1.com",
|
||||||
|
@ -809,25 +810,25 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
infoDomainNoHost = fakedEppObject(
|
infoDomainNoHost = fakedEppObject(
|
||||||
"my-nameserver.gov",
|
"my-nameserver.gov",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[],
|
contacts=[],
|
||||||
hosts=[],
|
hosts=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
infoDomainTwoHosts = fakedEppObject(
|
infoDomainTwoHosts = fakedEppObject(
|
||||||
"my-nameserver.gov",
|
"my-nameserver.gov",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[],
|
contacts=[],
|
||||||
hosts=["ns1.my-nameserver-1.com", "ns1.my-nameserver-2.com"],
|
hosts=["ns1.my-nameserver-1.com", "ns1.my-nameserver-2.com"],
|
||||||
)
|
)
|
||||||
|
|
||||||
mockDataInfoHosts = fakedEppObject(
|
mockDataInfoHosts = fakedEppObject(
|
||||||
"lastPw",
|
"lastPw",
|
||||||
cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 8, 25, 19, 45, 35)),
|
||||||
addrs=[common.Ip(addr="1.2.3.4"), common.Ip(addr="2.3.4.5")],
|
addrs=[common.Ip(addr="1.2.3.4"), common.Ip(addr="2.3.4.5")],
|
||||||
)
|
)
|
||||||
|
|
||||||
mockDataHostChange = fakedEppObject("lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35))
|
mockDataHostChange = fakedEppObject("lastPw", cr_date=make_aware(datetime.datetime(2023, 8, 25, 19, 45, 35)))
|
||||||
addDsData1 = {
|
addDsData1 = {
|
||||||
"keyTag": 1234,
|
"keyTag": 1234,
|
||||||
"alg": 3,
|
"alg": 3,
|
||||||
|
@ -859,7 +860,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
infoDomainHasIP = fakedEppObject(
|
infoDomainHasIP = fakedEppObject(
|
||||||
"nameserverwithip.gov",
|
"nameserverwithip.gov",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="securityContact",
|
contact="securityContact",
|
||||||
|
@ -884,7 +885,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
justNameserver = fakedEppObject(
|
justNameserver = fakedEppObject(
|
||||||
"justnameserver.com",
|
"justnameserver.com",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[
|
contacts=[
|
||||||
common.DomainContact(
|
common.DomainContact(
|
||||||
contact="securityContact",
|
contact="securityContact",
|
||||||
|
@ -907,7 +908,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
infoDomainCheckHostIPCombo = fakedEppObject(
|
infoDomainCheckHostIPCombo = fakedEppObject(
|
||||||
"nameserversubdomain.gov",
|
"nameserversubdomain.gov",
|
||||||
cr_date=datetime.datetime(2023, 5, 25, 19, 45, 35),
|
cr_date=make_aware(datetime.datetime(2023, 5, 25, 19, 45, 35)),
|
||||||
contacts=[],
|
contacts=[],
|
||||||
hosts=[
|
hosts=[
|
||||||
"ns1.nameserversubdomain.gov",
|
"ns1.nameserversubdomain.gov",
|
||||||
|
|
|
@ -59,22 +59,22 @@ class TestDomainAdmin(MockEppLib):
|
||||||
"""
|
"""
|
||||||
Make sure the short name is displaying in admin on the list page
|
Make sure the short name is displaying in admin on the list page
|
||||||
"""
|
"""
|
||||||
self.client.force_login(self.superuser)
|
with less_console_noise():
|
||||||
application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW)
|
self.client.force_login(self.superuser)
|
||||||
mock_client = MockSESClient()
|
application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW)
|
||||||
with boto3_mocking.clients.handler_for("sesv2", mock_client):
|
mock_client = MockSESClient()
|
||||||
with less_console_noise():
|
with boto3_mocking.clients.handler_for("sesv2", mock_client):
|
||||||
application.approve()
|
application.approve()
|
||||||
|
|
||||||
response = self.client.get("/admin/registrar/domain/")
|
response = self.client.get("/admin/registrar/domain/")
|
||||||
|
|
||||||
# There are 3 template references to Federal (3) plus one reference in the table
|
# There are 3 template references to Federal (3) plus one reference in the table
|
||||||
# for our actual application
|
# for our actual application
|
||||||
self.assertContains(response, "Federal", count=4)
|
self.assertContains(response, "Federal", count=4)
|
||||||
# This may be a bit more robust
|
# This may be a bit more robust
|
||||||
self.assertContains(response, '<td class="field-organization_type">Federal</td>', count=1)
|
self.assertContains(response, '<td class="field-organization_type">Federal</td>', count=1)
|
||||||
# Now let's make sure the long description does not exist
|
# Now let's make sure the long description does not exist
|
||||||
self.assertNotContains(response, "Federal: an agency of the U.S. government")
|
self.assertNotContains(response, "Federal: an agency of the U.S. government")
|
||||||
|
|
||||||
@skip("Why did this test stop working, and is is a good test")
|
@skip("Why did this test stop working, and is is a good test")
|
||||||
def test_place_and_remove_hold(self):
|
def test_place_and_remove_hold(self):
|
||||||
|
@ -120,40 +120,37 @@ class TestDomainAdmin(MockEppLib):
|
||||||
Then a user-friendly success message is returned for displaying on the web
|
Then a user-friendly success message is returned for displaying on the web
|
||||||
And `state` is et to `DELETED`
|
And `state` is et to `DELETED`
|
||||||
"""
|
"""
|
||||||
domain = create_ready_domain()
|
with less_console_noise():
|
||||||
# Put in client hold
|
domain = create_ready_domain()
|
||||||
domain.place_client_hold()
|
# Put in client hold
|
||||||
p = "userpass"
|
domain.place_client_hold()
|
||||||
self.client.login(username="staffuser", password=p)
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
# Ensure everything is displaying correctly
|
# Ensure everything is displaying correctly
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
follow=True,
|
follow=True,
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, domain.name)
|
|
||||||
self.assertContains(response, "Remove from registry")
|
|
||||||
|
|
||||||
# Test the info dialog
|
|
||||||
request = self.factory.post(
|
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
|
||||||
{"_delete_domain": "Remove from registry", "name": domain.name},
|
|
||||||
follow=True,
|
|
||||||
)
|
|
||||||
request.user = self.client
|
|
||||||
|
|
||||||
with patch("django.contrib.messages.add_message") as mock_add_message:
|
|
||||||
self.admin.do_delete_domain(request, domain)
|
|
||||||
mock_add_message.assert_called_once_with(
|
|
||||||
request,
|
|
||||||
messages.INFO,
|
|
||||||
"Domain city.gov has been deleted. Thanks!",
|
|
||||||
extra_tags="",
|
|
||||||
fail_silently=False,
|
|
||||||
)
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(domain.state, Domain.State.DELETED)
|
self.assertContains(response, domain.name)
|
||||||
|
self.assertContains(response, "Remove from registry")
|
||||||
|
# Test the info dialog
|
||||||
|
request = self.factory.post(
|
||||||
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
|
{"_delete_domain": "Remove from registry", "name": domain.name},
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
request.user = self.client
|
||||||
|
with patch("django.contrib.messages.add_message") as mock_add_message:
|
||||||
|
self.admin.do_delete_domain(request, domain)
|
||||||
|
mock_add_message.assert_called_once_with(
|
||||||
|
request,
|
||||||
|
messages.INFO,
|
||||||
|
"Domain city.gov has been deleted. Thanks!",
|
||||||
|
extra_tags="",
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
self.assertEqual(domain.state, Domain.State.DELETED)
|
||||||
|
|
||||||
def test_deletion_ready_fsm_failure(self):
|
def test_deletion_ready_fsm_failure(self):
|
||||||
"""
|
"""
|
||||||
|
@ -162,38 +159,36 @@ class TestDomainAdmin(MockEppLib):
|
||||||
Then a user-friendly error message is returned for displaying on the web
|
Then a user-friendly error message is returned for displaying on the web
|
||||||
And `state` is not set to `DELETED`
|
And `state` is not set to `DELETED`
|
||||||
"""
|
"""
|
||||||
domain = create_ready_domain()
|
with less_console_noise():
|
||||||
p = "userpass"
|
domain = create_ready_domain()
|
||||||
self.client.login(username="staffuser", password=p)
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
# Ensure everything is displaying correctly
|
# Ensure everything is displaying correctly
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
follow=True,
|
follow=True,
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, domain.name)
|
|
||||||
self.assertContains(response, "Remove from registry")
|
|
||||||
|
|
||||||
# Test the error
|
|
||||||
request = self.factory.post(
|
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
|
||||||
{"_delete_domain": "Remove from registry", "name": domain.name},
|
|
||||||
follow=True,
|
|
||||||
)
|
|
||||||
request.user = self.client
|
|
||||||
|
|
||||||
with patch("django.contrib.messages.add_message") as mock_add_message:
|
|
||||||
self.admin.do_delete_domain(request, domain)
|
|
||||||
mock_add_message.assert_called_once_with(
|
|
||||||
request,
|
|
||||||
messages.ERROR,
|
|
||||||
"Error deleting this Domain: "
|
|
||||||
"Can't switch from state 'ready' to 'deleted'"
|
|
||||||
", must be either 'dns_needed' or 'on_hold'",
|
|
||||||
extra_tags="",
|
|
||||||
fail_silently=False,
|
|
||||||
)
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertContains(response, domain.name)
|
||||||
|
self.assertContains(response, "Remove from registry")
|
||||||
|
# Test the error
|
||||||
|
request = self.factory.post(
|
||||||
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
|
{"_delete_domain": "Remove from registry", "name": domain.name},
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
request.user = self.client
|
||||||
|
with patch("django.contrib.messages.add_message") as mock_add_message:
|
||||||
|
self.admin.do_delete_domain(request, domain)
|
||||||
|
mock_add_message.assert_called_once_with(
|
||||||
|
request,
|
||||||
|
messages.ERROR,
|
||||||
|
"Error deleting this Domain: "
|
||||||
|
"Can't switch from state 'ready' to 'deleted'"
|
||||||
|
", must be either 'dns_needed' or 'on_hold'",
|
||||||
|
extra_tags="",
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(domain.state, Domain.State.READY)
|
self.assertEqual(domain.state, Domain.State.READY)
|
||||||
|
|
||||||
|
@ -205,62 +200,57 @@ class TestDomainAdmin(MockEppLib):
|
||||||
Then `commands.DeleteDomain` is sent to the registry
|
Then `commands.DeleteDomain` is sent to the registry
|
||||||
And Domain returns normally without an error dialog
|
And Domain returns normally without an error dialog
|
||||||
"""
|
"""
|
||||||
domain = create_ready_domain()
|
with less_console_noise():
|
||||||
# Put in client hold
|
domain = create_ready_domain()
|
||||||
domain.place_client_hold()
|
# Put in client hold
|
||||||
p = "userpass"
|
domain.place_client_hold()
|
||||||
self.client.login(username="staffuser", password=p)
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
# Ensure everything is displaying correctly
|
# Ensure everything is displaying correctly
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
follow=True,
|
follow=True,
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, domain.name)
|
|
||||||
self.assertContains(response, "Remove from registry")
|
|
||||||
|
|
||||||
# Test the info dialog
|
|
||||||
request = self.factory.post(
|
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
|
||||||
{"_delete_domain": "Remove from registry", "name": domain.name},
|
|
||||||
follow=True,
|
|
||||||
)
|
|
||||||
request.user = self.client
|
|
||||||
|
|
||||||
# Delete it once
|
|
||||||
with patch("django.contrib.messages.add_message") as mock_add_message:
|
|
||||||
self.admin.do_delete_domain(request, domain)
|
|
||||||
mock_add_message.assert_called_once_with(
|
|
||||||
request,
|
|
||||||
messages.INFO,
|
|
||||||
"Domain city.gov has been deleted. Thanks!",
|
|
||||||
extra_tags="",
|
|
||||||
fail_silently=False,
|
|
||||||
)
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(domain.state, Domain.State.DELETED)
|
self.assertContains(response, domain.name)
|
||||||
|
self.assertContains(response, "Remove from registry")
|
||||||
# Try to delete it again
|
# Test the info dialog
|
||||||
# Test the info dialog
|
request = self.factory.post(
|
||||||
request = self.factory.post(
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
{"_delete_domain": "Remove from registry", "name": domain.name},
|
||||||
{"_delete_domain": "Remove from registry", "name": domain.name},
|
follow=True,
|
||||||
follow=True,
|
|
||||||
)
|
|
||||||
request.user = self.client
|
|
||||||
|
|
||||||
with patch("django.contrib.messages.add_message") as mock_add_message:
|
|
||||||
self.admin.do_delete_domain(request, domain)
|
|
||||||
mock_add_message.assert_called_once_with(
|
|
||||||
request,
|
|
||||||
messages.INFO,
|
|
||||||
"This domain is already deleted",
|
|
||||||
extra_tags="",
|
|
||||||
fail_silently=False,
|
|
||||||
)
|
)
|
||||||
|
request.user = self.client
|
||||||
|
# Delete it once
|
||||||
|
with patch("django.contrib.messages.add_message") as mock_add_message:
|
||||||
|
self.admin.do_delete_domain(request, domain)
|
||||||
|
mock_add_message.assert_called_once_with(
|
||||||
|
request,
|
||||||
|
messages.INFO,
|
||||||
|
"Domain city.gov has been deleted. Thanks!",
|
||||||
|
extra_tags="",
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(domain.state, Domain.State.DELETED)
|
self.assertEqual(domain.state, Domain.State.DELETED)
|
||||||
|
# Try to delete it again
|
||||||
|
# Test the info dialog
|
||||||
|
request = self.factory.post(
|
||||||
|
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||||
|
{"_delete_domain": "Remove from registry", "name": domain.name},
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
request.user = self.client
|
||||||
|
with patch("django.contrib.messages.add_message") as mock_add_message:
|
||||||
|
self.admin.do_delete_domain(request, domain)
|
||||||
|
mock_add_message.assert_called_once_with(
|
||||||
|
request,
|
||||||
|
messages.INFO,
|
||||||
|
"This domain is already deleted",
|
||||||
|
extra_tags="",
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
self.assertEqual(domain.state, Domain.State.DELETED)
|
||||||
|
|
||||||
@skip("Waiting on epp lib to implement")
|
@skip("Waiting on epp lib to implement")
|
||||||
def test_place_and_remove_hold_epp(self):
|
def test_place_and_remove_hold_epp(self):
|
||||||
|
@ -642,6 +632,7 @@ class TestDomainApplicationAdmin(MockEppLib):
|
||||||
"creator",
|
"creator",
|
||||||
"about_your_organization",
|
"about_your_organization",
|
||||||
"requested_domain",
|
"requested_domain",
|
||||||
|
"approved_domain",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
"purpose",
|
"purpose",
|
||||||
"submitter",
|
"submitter",
|
||||||
|
@ -1067,7 +1058,7 @@ class DomainInvitationAdminTest(TestCase):
|
||||||
self.assertContains(response, retrieved_html, count=1)
|
self.assertContains(response, retrieved_html, count=1)
|
||||||
|
|
||||||
|
|
||||||
class DomainInformationAdminTest(TestCase):
|
class TestDomainInformationAdmin(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Setup environment for a mock admin user"""
|
"""Setup environment for a mock admin user"""
|
||||||
self.site = AdminSite()
|
self.site = AdminSite()
|
||||||
|
@ -1075,6 +1066,7 @@ class DomainInformationAdminTest(TestCase):
|
||||||
self.admin = DomainInformationAdmin(model=DomainInformation, admin_site=self.site)
|
self.admin = DomainInformationAdmin(model=DomainInformation, admin_site=self.site)
|
||||||
self.client = Client(HTTP_HOST="localhost:8080")
|
self.client = Client(HTTP_HOST="localhost:8080")
|
||||||
self.superuser = create_superuser()
|
self.superuser = create_superuser()
|
||||||
|
self.staffuser = create_user()
|
||||||
self.mock_data_generator = AuditedAdminMockData()
|
self.mock_data_generator = AuditedAdminMockData()
|
||||||
|
|
||||||
self.test_helper = GenericTestHelper(
|
self.test_helper = GenericTestHelper(
|
||||||
|
@ -1118,6 +1110,27 @@ class DomainInformationAdminTest(TestCase):
|
||||||
Contact.objects.all().delete()
|
Contact.objects.all().delete()
|
||||||
User.objects.all().delete()
|
User.objects.all().delete()
|
||||||
|
|
||||||
|
def test_readonly_fields_for_analyst(self):
|
||||||
|
"""Ensures that analysts have their permissions setup correctly"""
|
||||||
|
request = self.factory.get("/")
|
||||||
|
request.user = self.staffuser
|
||||||
|
|
||||||
|
readonly_fields = self.admin.get_readonly_fields(request)
|
||||||
|
|
||||||
|
expected_fields = [
|
||||||
|
"creator",
|
||||||
|
"type_of_work",
|
||||||
|
"more_organization_information",
|
||||||
|
"domain",
|
||||||
|
"domain_application",
|
||||||
|
"submitter",
|
||||||
|
"no_other_contacts_rationale",
|
||||||
|
"anything_else",
|
||||||
|
"is_policy_acknowledged",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(readonly_fields, expected_fields)
|
||||||
|
|
||||||
def test_domain_sortable(self):
|
def test_domain_sortable(self):
|
||||||
"""Tests if DomainInformation sorts by domain correctly"""
|
"""Tests if DomainInformation sorts by domain correctly"""
|
||||||
p = "adminpass"
|
p = "adminpass"
|
||||||
|
@ -1282,64 +1295,62 @@ class ListHeaderAdminTest(TestCase):
|
||||||
self.superuser = create_superuser()
|
self.superuser = create_superuser()
|
||||||
|
|
||||||
def test_changelist_view(self):
|
def test_changelist_view(self):
|
||||||
# Have to get creative to get past linter
|
with less_console_noise():
|
||||||
p = "adminpass"
|
# Have to get creative to get past linter
|
||||||
self.client.login(username="superuser", password=p)
|
p = "adminpass"
|
||||||
|
self.client.login(username="superuser", password=p)
|
||||||
# Mock a user
|
# Mock a user
|
||||||
user = mock_user()
|
user = mock_user()
|
||||||
|
# Make the request using the Client class
|
||||||
# Make the request using the Client class
|
# which handles CSRF
|
||||||
# which handles CSRF
|
# Follow=True handles the redirect
|
||||||
# Follow=True handles the redirect
|
response = self.client.get(
|
||||||
response = self.client.get(
|
"/admin/registrar/domainapplication/",
|
||||||
"/admin/registrar/domainapplication/",
|
|
||||||
{
|
|
||||||
"status__exact": "started",
|
|
||||||
"investigator__id__exact": user.id,
|
|
||||||
"q": "Hello",
|
|
||||||
},
|
|
||||||
follow=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Assert that the filters and search_query are added to the extra_context
|
|
||||||
self.assertIn("filters", response.context)
|
|
||||||
self.assertIn("search_query", response.context)
|
|
||||||
# Assert the content of filters and search_query
|
|
||||||
filters = response.context["filters"]
|
|
||||||
search_query = response.context["search_query"]
|
|
||||||
self.assertEqual(search_query, "Hello")
|
|
||||||
self.assertEqual(
|
|
||||||
filters,
|
|
||||||
[
|
|
||||||
{"parameter_name": "status", "parameter_value": "started"},
|
|
||||||
{
|
{
|
||||||
"parameter_name": "investigator",
|
"status__exact": "started",
|
||||||
"parameter_value": user.first_name + " " + user.last_name,
|
"investigator__id__exact": user.id,
|
||||||
|
"q": "Hello",
|
||||||
},
|
},
|
||||||
],
|
follow=True,
|
||||||
)
|
)
|
||||||
|
# Assert that the filters and search_query are added to the extra_context
|
||||||
|
self.assertIn("filters", response.context)
|
||||||
|
self.assertIn("search_query", response.context)
|
||||||
|
# Assert the content of filters and search_query
|
||||||
|
filters = response.context["filters"]
|
||||||
|
search_query = response.context["search_query"]
|
||||||
|
self.assertEqual(search_query, "Hello")
|
||||||
|
self.assertEqual(
|
||||||
|
filters,
|
||||||
|
[
|
||||||
|
{"parameter_name": "status", "parameter_value": "started"},
|
||||||
|
{
|
||||||
|
"parameter_name": "investigator",
|
||||||
|
"parameter_value": user.first_name + " " + user.last_name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_filters(self):
|
def test_get_filters(self):
|
||||||
# Create a mock request object
|
with less_console_noise():
|
||||||
request = self.factory.get("/admin/yourmodel/")
|
# Create a mock request object
|
||||||
# Set the GET parameters for testing
|
request = self.factory.get("/admin/yourmodel/")
|
||||||
request.GET = {
|
# Set the GET parameters for testing
|
||||||
"status": "started",
|
request.GET = {
|
||||||
"investigator": "Jeff Lebowski",
|
"status": "started",
|
||||||
"q": "search_value",
|
"investigator": "Jeff Lebowski",
|
||||||
}
|
"q": "search_value",
|
||||||
# Call the get_filters method
|
}
|
||||||
filters = self.admin.get_filters(request)
|
# Call the get_filters method
|
||||||
|
filters = self.admin.get_filters(request)
|
||||||
# Assert the filters extracted from the request GET
|
# Assert the filters extracted from the request GET
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
filters,
|
filters,
|
||||||
[
|
[
|
||||||
{"parameter_name": "status", "parameter_value": "started"},
|
{"parameter_name": "status", "parameter_value": "started"},
|
||||||
{"parameter_name": "investigator", "parameter_value": "Jeff Lebowski"},
|
{"parameter_name": "investigator", "parameter_value": "Jeff Lebowski"},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# delete any applications too
|
# delete any applications too
|
||||||
|
@ -1778,42 +1789,38 @@ class ContactAdminTest(TestCase):
|
||||||
def test_change_view_for_joined_contact_five_or_more(self):
|
def test_change_view_for_joined_contact_five_or_more(self):
|
||||||
"""Create a contact, join it to 5 domain requests. The 6th join will be a user.
|
"""Create a contact, join it to 5 domain requests. The 6th join will be a user.
|
||||||
Assert that the warning on the contact form lists 5 joins and a '1 more' ellispsis."""
|
Assert that the warning on the contact form lists 5 joins and a '1 more' ellispsis."""
|
||||||
|
with less_console_noise():
|
||||||
self.client.force_login(self.superuser)
|
self.client.force_login(self.superuser)
|
||||||
|
# Create an instance of the model
|
||||||
# Create an instance of the model
|
# join it to 5 domain requests. The 6th join will be a user.
|
||||||
# join it to 5 domain requests. The 6th join will be a user.
|
contact, _ = Contact.objects.get_or_create(user=self.staffuser)
|
||||||
contact, _ = Contact.objects.get_or_create(user=self.staffuser)
|
application1 = completed_application(submitter=contact, name="city1.gov")
|
||||||
application1 = completed_application(submitter=contact, name="city1.gov")
|
application2 = completed_application(submitter=contact, name="city2.gov")
|
||||||
application2 = completed_application(submitter=contact, name="city2.gov")
|
application3 = completed_application(submitter=contact, name="city3.gov")
|
||||||
application3 = completed_application(submitter=contact, name="city3.gov")
|
application4 = completed_application(submitter=contact, name="city4.gov")
|
||||||
application4 = completed_application(submitter=contact, name="city4.gov")
|
application5 = completed_application(submitter=contact, name="city5.gov")
|
||||||
application5 = completed_application(submitter=contact, name="city5.gov")
|
with patch("django.contrib.messages.warning") as mock_warning:
|
||||||
|
# Use the test client to simulate the request
|
||||||
with patch("django.contrib.messages.warning") as mock_warning:
|
response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk]))
|
||||||
# Use the test client to simulate the request
|
logger.debug(mock_warning)
|
||||||
response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk]))
|
# Assert that the error message was called with the correct argument
|
||||||
|
# Note: The 6th join will be a user.
|
||||||
logger.info(mock_warning)
|
mock_warning.assert_called_once_with(
|
||||||
|
response.wsgi_request,
|
||||||
# Assert that the error message was called with the correct argument
|
"<ul class='messagelist_content-list--unstyled'>"
|
||||||
# Note: The 6th join will be a user.
|
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
||||||
mock_warning.assert_called_once_with(
|
f"domainapplication/{application1.pk}/change/'>city1.gov</a></li>"
|
||||||
response.wsgi_request,
|
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
||||||
"<ul class='messagelist_content-list--unstyled'>"
|
f"domainapplication/{application2.pk}/change/'>city2.gov</a></li>"
|
||||||
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
||||||
f"domainapplication/{application1.pk}/change/'>city1.gov</a></li>"
|
f"domainapplication/{application3.pk}/change/'>city3.gov</a></li>"
|
||||||
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
||||||
f"domainapplication/{application2.pk}/change/'>city2.gov</a></li>"
|
f"domainapplication/{application4.pk}/change/'>city4.gov</a></li>"
|
||||||
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
||||||
f"domainapplication/{application3.pk}/change/'>city3.gov</a></li>"
|
f"domainapplication/{application5.pk}/change/'>city5.gov</a></li>"
|
||||||
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
"</ul>"
|
||||||
f"domainapplication/{application4.pk}/change/'>city4.gov</a></li>"
|
"<p class='font-sans-3xs'>And 1 more...</p>",
|
||||||
"<li>Joined to DomainApplication: <a href='/admin/registrar/"
|
)
|
||||||
f"domainapplication/{application5.pk}/change/'>city5.gov</a></li>"
|
|
||||||
"</ul>"
|
|
||||||
"<p class='font-sans-3xs'>And 1 more...</p>",
|
|
||||||
)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
DomainApplication.objects.all().delete()
|
DomainApplication.objects.all().delete()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
from datetime import date, datetime, time
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ from django.core.management import call_command
|
||||||
from unittest.mock import patch, call
|
from unittest.mock import patch, call
|
||||||
from epplibwrapper import commands, common
|
from epplibwrapper import commands, common
|
||||||
|
|
||||||
from .common import MockEppLib
|
from .common import MockEppLib, less_console_noise
|
||||||
|
|
||||||
|
|
||||||
class TestPopulateFirstReady(TestCase):
|
class TestPopulateFirstReady(TestCase):
|
||||||
|
@ -33,7 +34,9 @@ class TestPopulateFirstReady(TestCase):
|
||||||
self.unknown_domain, _ = Domain.objects.get_or_create(name="fakeunknown.gov", state=Domain.State.UNKNOWN)
|
self.unknown_domain, _ = Domain.objects.get_or_create(name="fakeunknown.gov", state=Domain.State.UNKNOWN)
|
||||||
|
|
||||||
# Set a ready_at date for testing purposes
|
# Set a ready_at date for testing purposes
|
||||||
self.ready_at_date = datetime.date(2022, 12, 31)
|
self.ready_at_date = date(2022, 12, 31)
|
||||||
|
_ready_at_datetime = datetime.combine(self.ready_at_date, time.min)
|
||||||
|
self.ready_at_date_tz_aware = timezone.make_aware(_ready_at_datetime, timezone=timezone.utc)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Deletes all DB objects related to migrations"""
|
"""Deletes all DB objects related to migrations"""
|
||||||
|
@ -49,122 +52,103 @@ class TestPopulateFirstReady(TestCase):
|
||||||
The 'call_command' function from Django's management framework is then used to
|
The 'call_command' function from Django's management framework is then used to
|
||||||
execute the populate_first_ready command with the specified arguments.
|
execute the populate_first_ready command with the specified arguments.
|
||||||
"""
|
"""
|
||||||
with patch(
|
with less_console_noise():
|
||||||
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
with patch(
|
||||||
return_value=True,
|
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
||||||
):
|
return_value=True,
|
||||||
call_command("populate_first_ready")
|
):
|
||||||
|
call_command("populate_first_ready")
|
||||||
|
|
||||||
def test_populate_first_ready_state_ready(self):
|
def test_populate_first_ready_state_ready(self):
|
||||||
"""
|
"""
|
||||||
Tests that the populate_first_ready works as expected for the state 'ready'
|
Tests that the populate_first_ready works as expected for the state 'ready'
|
||||||
"""
|
"""
|
||||||
# Set the created at date
|
with less_console_noise():
|
||||||
self.ready_domain.created_at = self.ready_at_date
|
# Set the created at date
|
||||||
self.ready_domain.save()
|
self.ready_domain.created_at = self.ready_at_date_tz_aware
|
||||||
|
self.ready_domain.save()
|
||||||
desired_domain = copy.deepcopy(self.ready_domain)
|
desired_domain = copy.deepcopy(self.ready_domain)
|
||||||
|
desired_domain.first_ready = self.ready_at_date
|
||||||
desired_domain.first_ready = self.ready_at_date
|
# Run the expiration date script
|
||||||
|
self.run_populate_first_ready()
|
||||||
# Run the expiration date script
|
self.assertEqual(desired_domain, self.ready_domain)
|
||||||
self.run_populate_first_ready()
|
# Explicitly test the first_ready date
|
||||||
|
first_ready = Domain.objects.filter(name="fakeready.gov").get().first_ready
|
||||||
self.assertEqual(desired_domain, self.ready_domain)
|
self.assertEqual(first_ready, self.ready_at_date)
|
||||||
|
|
||||||
# Explicitly test the first_ready date
|
|
||||||
first_ready = Domain.objects.filter(name="fakeready.gov").get().first_ready
|
|
||||||
self.assertEqual(first_ready, self.ready_at_date)
|
|
||||||
|
|
||||||
def test_populate_first_ready_state_deleted(self):
|
def test_populate_first_ready_state_deleted(self):
|
||||||
"""
|
"""
|
||||||
Tests that the populate_first_ready works as expected for the state 'deleted'
|
Tests that the populate_first_ready works as expected for the state 'deleted'
|
||||||
"""
|
"""
|
||||||
# Set the created at date
|
with less_console_noise():
|
||||||
self.deleted_domain.created_at = self.ready_at_date
|
# Set the created at date
|
||||||
self.deleted_domain.save()
|
self.deleted_domain.created_at = self.ready_at_date_tz_aware
|
||||||
|
self.deleted_domain.save()
|
||||||
desired_domain = copy.deepcopy(self.deleted_domain)
|
desired_domain = copy.deepcopy(self.deleted_domain)
|
||||||
|
desired_domain.first_ready = self.ready_at_date
|
||||||
desired_domain.first_ready = self.ready_at_date
|
# Run the expiration date script
|
||||||
|
self.run_populate_first_ready()
|
||||||
# Run the expiration date script
|
self.assertEqual(desired_domain, self.deleted_domain)
|
||||||
self.run_populate_first_ready()
|
# Explicitly test the first_ready date
|
||||||
|
first_ready = Domain.objects.filter(name="fakedeleted.gov").get().first_ready
|
||||||
self.assertEqual(desired_domain, self.deleted_domain)
|
self.assertEqual(first_ready, self.ready_at_date)
|
||||||
|
|
||||||
# Explicitly test the first_ready date
|
|
||||||
first_ready = Domain.objects.filter(name="fakedeleted.gov").get().first_ready
|
|
||||||
self.assertEqual(first_ready, self.ready_at_date)
|
|
||||||
|
|
||||||
def test_populate_first_ready_state_dns_needed(self):
|
def test_populate_first_ready_state_dns_needed(self):
|
||||||
"""
|
"""
|
||||||
Tests that the populate_first_ready doesn't make changes when a domain's state is 'dns_needed'
|
Tests that the populate_first_ready doesn't make changes when a domain's state is 'dns_needed'
|
||||||
"""
|
"""
|
||||||
# Set the created at date
|
with less_console_noise():
|
||||||
self.dns_needed_domain.created_at = self.ready_at_date
|
# Set the created at date
|
||||||
self.dns_needed_domain.save()
|
self.dns_needed_domain.created_at = self.ready_at_date_tz_aware
|
||||||
|
self.dns_needed_domain.save()
|
||||||
desired_domain = copy.deepcopy(self.dns_needed_domain)
|
desired_domain = copy.deepcopy(self.dns_needed_domain)
|
||||||
|
desired_domain.first_ready = None
|
||||||
desired_domain.first_ready = None
|
# Run the expiration date script
|
||||||
|
self.run_populate_first_ready()
|
||||||
# Run the expiration date script
|
current_domain = self.dns_needed_domain
|
||||||
self.run_populate_first_ready()
|
# The object should largely be unaltered (does not test first_ready)
|
||||||
|
self.assertEqual(desired_domain, current_domain)
|
||||||
current_domain = self.dns_needed_domain
|
first_ready = Domain.objects.filter(name="fakedns.gov").get().first_ready
|
||||||
# The object should largely be unaltered (does not test first_ready)
|
# Explicitly test the first_ready date
|
||||||
self.assertEqual(desired_domain, current_domain)
|
self.assertNotEqual(first_ready, self.ready_at_date)
|
||||||
|
self.assertEqual(first_ready, None)
|
||||||
first_ready = Domain.objects.filter(name="fakedns.gov").get().first_ready
|
|
||||||
|
|
||||||
# Explicitly test the first_ready date
|
|
||||||
self.assertNotEqual(first_ready, self.ready_at_date)
|
|
||||||
self.assertEqual(first_ready, None)
|
|
||||||
|
|
||||||
def test_populate_first_ready_state_on_hold(self):
|
def test_populate_first_ready_state_on_hold(self):
|
||||||
"""
|
"""
|
||||||
Tests that the populate_first_ready works as expected for the state 'on_hold'
|
Tests that the populate_first_ready works as expected for the state 'on_hold'
|
||||||
"""
|
"""
|
||||||
self.hold_domain.created_at = self.ready_at_date
|
with less_console_noise():
|
||||||
self.hold_domain.save()
|
self.hold_domain.created_at = self.ready_at_date_tz_aware
|
||||||
|
self.hold_domain.save()
|
||||||
desired_domain = copy.deepcopy(self.hold_domain)
|
desired_domain = copy.deepcopy(self.hold_domain)
|
||||||
desired_domain.first_ready = self.ready_at_date
|
desired_domain.first_ready = self.ready_at_date
|
||||||
|
# Run the update first ready_at script
|
||||||
# Run the update first ready_at script
|
self.run_populate_first_ready()
|
||||||
self.run_populate_first_ready()
|
current_domain = self.hold_domain
|
||||||
|
self.assertEqual(desired_domain, current_domain)
|
||||||
current_domain = self.hold_domain
|
# Explicitly test the first_ready date
|
||||||
self.assertEqual(desired_domain, current_domain)
|
first_ready = Domain.objects.filter(name="fakehold.gov").get().first_ready
|
||||||
|
self.assertEqual(first_ready, self.ready_at_date)
|
||||||
# Explicitly test the first_ready date
|
|
||||||
first_ready = Domain.objects.filter(name="fakehold.gov").get().first_ready
|
|
||||||
self.assertEqual(first_ready, self.ready_at_date)
|
|
||||||
|
|
||||||
def test_populate_first_ready_state_unknown(self):
|
def test_populate_first_ready_state_unknown(self):
|
||||||
"""
|
"""
|
||||||
Tests that the populate_first_ready works as expected for the state 'unknown'
|
Tests that the populate_first_ready works as expected for the state 'unknown'
|
||||||
"""
|
"""
|
||||||
# Set the created at date
|
with less_console_noise():
|
||||||
self.unknown_domain.created_at = self.ready_at_date
|
# Set the created at date
|
||||||
self.unknown_domain.save()
|
self.unknown_domain.created_at = self.ready_at_date_tz_aware
|
||||||
|
self.unknown_domain.save()
|
||||||
desired_domain = copy.deepcopy(self.unknown_domain)
|
desired_domain = copy.deepcopy(self.unknown_domain)
|
||||||
desired_domain.first_ready = None
|
desired_domain.first_ready = None
|
||||||
|
# Run the expiration date script
|
||||||
# Run the expiration date script
|
self.run_populate_first_ready()
|
||||||
self.run_populate_first_ready()
|
current_domain = self.unknown_domain
|
||||||
|
# The object should largely be unaltered (does not test first_ready)
|
||||||
current_domain = self.unknown_domain
|
self.assertEqual(desired_domain, current_domain)
|
||||||
|
# Explicitly test the first_ready date
|
||||||
# The object should largely be unaltered (does not test first_ready)
|
first_ready = Domain.objects.filter(name="fakeunknown.gov").get().first_ready
|
||||||
self.assertEqual(desired_domain, current_domain)
|
self.assertNotEqual(first_ready, self.ready_at_date)
|
||||||
|
self.assertEqual(first_ready, None)
|
||||||
# Explicitly test the first_ready date
|
|
||||||
first_ready = Domain.objects.filter(name="fakeunknown.gov").get().first_ready
|
|
||||||
self.assertNotEqual(first_ready, self.ready_at_date)
|
|
||||||
self.assertEqual(first_ready, None)
|
|
||||||
|
|
||||||
|
|
||||||
class TestPatchAgencyInfo(TestCase):
|
class TestPatchAgencyInfo(TestCase):
|
||||||
|
@ -185,7 +169,8 @@ class TestPatchAgencyInfo(TestCase):
|
||||||
@patch("registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", return_value=True)
|
@patch("registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", return_value=True)
|
||||||
def call_patch_federal_agency_info(self, mock_prompt):
|
def call_patch_federal_agency_info(self, mock_prompt):
|
||||||
"""Calls the patch_federal_agency_info command and mimics a keypress"""
|
"""Calls the patch_federal_agency_info command and mimics a keypress"""
|
||||||
call_command("patch_federal_agency_info", "registrar/tests/data/fake_current_full.csv", debug=True)
|
with less_console_noise():
|
||||||
|
call_command("patch_federal_agency_info", "registrar/tests/data/fake_current_full.csv", debug=True)
|
||||||
|
|
||||||
def test_patch_agency_info(self):
|
def test_patch_agency_info(self):
|
||||||
"""
|
"""
|
||||||
|
@ -194,17 +179,14 @@ class TestPatchAgencyInfo(TestCase):
|
||||||
of a `DomainInformation` object when the corresponding
|
of a `DomainInformation` object when the corresponding
|
||||||
`TransitionDomain` object has a valid `federal_agency`.
|
`TransitionDomain` object has a valid `federal_agency`.
|
||||||
"""
|
"""
|
||||||
|
with less_console_noise():
|
||||||
# Ensure that the federal_agency is None
|
# Ensure that the federal_agency is None
|
||||||
self.assertEqual(self.domain_info.federal_agency, None)
|
self.assertEqual(self.domain_info.federal_agency, None)
|
||||||
|
self.call_patch_federal_agency_info()
|
||||||
self.call_patch_federal_agency_info()
|
# Reload the domain_info object from the database
|
||||||
|
self.domain_info.refresh_from_db()
|
||||||
# Reload the domain_info object from the database
|
# Check that the federal_agency field was updated
|
||||||
self.domain_info.refresh_from_db()
|
self.assertEqual(self.domain_info.federal_agency, "test agency")
|
||||||
|
|
||||||
# Check that the federal_agency field was updated
|
|
||||||
self.assertEqual(self.domain_info.federal_agency, "test agency")
|
|
||||||
|
|
||||||
def test_patch_agency_info_skip(self):
|
def test_patch_agency_info_skip(self):
|
||||||
"""
|
"""
|
||||||
|
@ -213,21 +195,18 @@ class TestPatchAgencyInfo(TestCase):
|
||||||
of a `DomainInformation` object when the corresponding
|
of a `DomainInformation` object when the corresponding
|
||||||
`TransitionDomain` object does not exist.
|
`TransitionDomain` object does not exist.
|
||||||
"""
|
"""
|
||||||
# Set federal_agency to None to simulate a skip
|
with less_console_noise():
|
||||||
self.transition_domain.federal_agency = None
|
# Set federal_agency to None to simulate a skip
|
||||||
self.transition_domain.save()
|
self.transition_domain.federal_agency = None
|
||||||
|
self.transition_domain.save()
|
||||||
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
|
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
|
||||||
self.call_patch_federal_agency_info()
|
self.call_patch_federal_agency_info()
|
||||||
|
# Check that the correct log message was output
|
||||||
# Check that the correct log message was output
|
self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
|
||||||
self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
|
# Reload the domain_info object from the database
|
||||||
|
self.domain_info.refresh_from_db()
|
||||||
# Reload the domain_info object from the database
|
# Check that the federal_agency field was not updated
|
||||||
self.domain_info.refresh_from_db()
|
self.assertIsNone(self.domain_info.federal_agency)
|
||||||
|
|
||||||
# Check that the federal_agency field was not updated
|
|
||||||
self.assertIsNone(self.domain_info.federal_agency)
|
|
||||||
|
|
||||||
def test_patch_agency_info_skip_updates_data(self):
|
def test_patch_agency_info_skip_updates_data(self):
|
||||||
"""
|
"""
|
||||||
|
@ -235,25 +214,21 @@ class TestPatchAgencyInfo(TestCase):
|
||||||
updates the DomainInformation object, because a record exists in the
|
updates the DomainInformation object, because a record exists in the
|
||||||
provided current-full.csv file.
|
provided current-full.csv file.
|
||||||
"""
|
"""
|
||||||
# Set federal_agency to None to simulate a skip
|
with less_console_noise():
|
||||||
self.transition_domain.federal_agency = None
|
# Set federal_agency to None to simulate a skip
|
||||||
self.transition_domain.save()
|
self.transition_domain.federal_agency = None
|
||||||
|
self.transition_domain.save()
|
||||||
# Change the domain name to something parsable in the .csv
|
# Change the domain name to something parsable in the .csv
|
||||||
self.domain.name = "cdomain1.gov"
|
self.domain.name = "cdomain1.gov"
|
||||||
self.domain.save()
|
self.domain.save()
|
||||||
|
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
|
||||||
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="WARNING") as context:
|
self.call_patch_federal_agency_info()
|
||||||
self.call_patch_federal_agency_info()
|
# Check that the correct log message was output
|
||||||
|
self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
|
||||||
# Check that the correct log message was output
|
# Reload the domain_info object from the database
|
||||||
self.assertIn("SOME AGENCY DATA WAS NONE", context.output[0])
|
self.domain_info.refresh_from_db()
|
||||||
|
# Check that the federal_agency field was not updated
|
||||||
# Reload the domain_info object from the database
|
self.assertEqual(self.domain_info.federal_agency, "World War I Centennial Commission")
|
||||||
self.domain_info.refresh_from_db()
|
|
||||||
|
|
||||||
# Check that the federal_agency field was not updated
|
|
||||||
self.assertEqual(self.domain_info.federal_agency, "World War I Centennial Commission")
|
|
||||||
|
|
||||||
def test_patch_agency_info_skips_valid_domains(self):
|
def test_patch_agency_info_skips_valid_domains(self):
|
||||||
"""
|
"""
|
||||||
|
@ -261,20 +236,17 @@ class TestPatchAgencyInfo(TestCase):
|
||||||
does not update the `federal_agency` field
|
does not update the `federal_agency` field
|
||||||
of a `DomainInformation` object
|
of a `DomainInformation` object
|
||||||
"""
|
"""
|
||||||
self.domain_info.federal_agency = "unchanged"
|
with less_console_noise():
|
||||||
self.domain_info.save()
|
self.domain_info.federal_agency = "unchanged"
|
||||||
|
self.domain_info.save()
|
||||||
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="INFO") as context:
|
with self.assertLogs("registrar.management.commands.patch_federal_agency_info", level="INFO") as context:
|
||||||
self.call_patch_federal_agency_info()
|
self.call_patch_federal_agency_info()
|
||||||
|
# Check that the correct log message was output
|
||||||
# Check that the correct log message was output
|
self.assertIn("FINISHED", context.output[1])
|
||||||
self.assertIn("FINISHED", context.output[1])
|
# Reload the domain_info object from the database
|
||||||
|
self.domain_info.refresh_from_db()
|
||||||
# Reload the domain_info object from the database
|
# Check that the federal_agency field was not updated
|
||||||
self.domain_info.refresh_from_db()
|
self.assertEqual(self.domain_info.federal_agency, "unchanged")
|
||||||
|
|
||||||
# Check that the federal_agency field was not updated
|
|
||||||
self.assertEqual(self.domain_info.federal_agency, "unchanged")
|
|
||||||
|
|
||||||
|
|
||||||
class TestExtendExpirationDates(MockEppLib):
|
class TestExtendExpirationDates(MockEppLib):
|
||||||
|
@ -283,39 +255,37 @@ class TestExtendExpirationDates(MockEppLib):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
# Create a valid domain that is updatable
|
# Create a valid domain that is updatable
|
||||||
Domain.objects.get_or_create(
|
Domain.objects.get_or_create(
|
||||||
name="waterbutpurple.gov", state=Domain.State.READY, expiration_date=datetime.date(2023, 11, 15)
|
name="waterbutpurple.gov", state=Domain.State.READY, expiration_date=date(2023, 11, 15)
|
||||||
)
|
)
|
||||||
TransitionDomain.objects.get_or_create(
|
TransitionDomain.objects.get_or_create(
|
||||||
username="testytester@mail.com",
|
username="testytester@mail.com",
|
||||||
domain_name="waterbutpurple.gov",
|
domain_name="waterbutpurple.gov",
|
||||||
epp_expiration_date=datetime.date(2023, 11, 15),
|
epp_expiration_date=date(2023, 11, 15),
|
||||||
)
|
)
|
||||||
# Create a domain with an invalid expiration date
|
# Create a domain with an invalid expiration date
|
||||||
Domain.objects.get_or_create(
|
Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY, expiration_date=date(2022, 5, 25))
|
||||||
name="fake.gov", state=Domain.State.READY, expiration_date=datetime.date(2022, 5, 25)
|
|
||||||
)
|
|
||||||
TransitionDomain.objects.get_or_create(
|
TransitionDomain.objects.get_or_create(
|
||||||
username="themoonisactuallycheese@mail.com",
|
username="themoonisactuallycheese@mail.com",
|
||||||
domain_name="fake.gov",
|
domain_name="fake.gov",
|
||||||
epp_expiration_date=datetime.date(2022, 5, 25),
|
epp_expiration_date=date(2022, 5, 25),
|
||||||
)
|
)
|
||||||
# Create a domain with an invalid state
|
# Create a domain with an invalid state
|
||||||
Domain.objects.get_or_create(
|
Domain.objects.get_or_create(
|
||||||
name="fakeneeded.gov", state=Domain.State.DNS_NEEDED, expiration_date=datetime.date(2023, 11, 15)
|
name="fakeneeded.gov", state=Domain.State.DNS_NEEDED, expiration_date=date(2023, 11, 15)
|
||||||
)
|
)
|
||||||
TransitionDomain.objects.get_or_create(
|
TransitionDomain.objects.get_or_create(
|
||||||
username="fakeneeded@mail.com",
|
username="fakeneeded@mail.com",
|
||||||
domain_name="fakeneeded.gov",
|
domain_name="fakeneeded.gov",
|
||||||
epp_expiration_date=datetime.date(2023, 11, 15),
|
epp_expiration_date=date(2023, 11, 15),
|
||||||
)
|
)
|
||||||
# Create a domain with a date greater than the maximum
|
# Create a domain with a date greater than the maximum
|
||||||
Domain.objects.get_or_create(
|
Domain.objects.get_or_create(
|
||||||
name="fakemaximum.gov", state=Domain.State.READY, expiration_date=datetime.date(2024, 12, 31)
|
name="fakemaximum.gov", state=Domain.State.READY, expiration_date=date(2024, 12, 31)
|
||||||
)
|
)
|
||||||
TransitionDomain.objects.get_or_create(
|
TransitionDomain.objects.get_or_create(
|
||||||
username="fakemaximum@mail.com",
|
username="fakemaximum@mail.com",
|
||||||
domain_name="fakemaximum.gov",
|
domain_name="fakemaximum.gov",
|
||||||
epp_expiration_date=datetime.date(2024, 12, 31),
|
epp_expiration_date=date(2024, 12, 31),
|
||||||
)
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -338,83 +308,82 @@ class TestExtendExpirationDates(MockEppLib):
|
||||||
The 'call_command' function from Django's management framework is then used to
|
The 'call_command' function from Django's management framework is then used to
|
||||||
execute the extend_expiration_dates command with the specified arguments.
|
execute the extend_expiration_dates command with the specified arguments.
|
||||||
"""
|
"""
|
||||||
with patch(
|
with less_console_noise():
|
||||||
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
with patch(
|
||||||
return_value=True,
|
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
||||||
):
|
return_value=True,
|
||||||
call_command("extend_expiration_dates")
|
):
|
||||||
|
call_command("extend_expiration_dates")
|
||||||
|
|
||||||
def test_extends_expiration_date_correctly(self):
|
def test_extends_expiration_date_correctly(self):
|
||||||
"""
|
"""
|
||||||
Tests that the extend_expiration_dates method extends dates as expected
|
Tests that the extend_expiration_dates method extends dates as expected
|
||||||
"""
|
"""
|
||||||
desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
with less_console_noise():
|
||||||
desired_domain.expiration_date = datetime.date(2024, 11, 15)
|
desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
||||||
|
desired_domain.expiration_date = date(2024, 11, 15)
|
||||||
# Run the expiration date script
|
# Run the expiration date script
|
||||||
self.run_extend_expiration_dates()
|
self.run_extend_expiration_dates()
|
||||||
|
current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
||||||
current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
self.assertEqual(desired_domain, current_domain)
|
||||||
|
# Explicitly test the expiration date
|
||||||
self.assertEqual(desired_domain, current_domain)
|
self.assertEqual(current_domain.expiration_date, date(2024, 11, 15))
|
||||||
# Explicitly test the expiration date
|
|
||||||
self.assertEqual(current_domain.expiration_date, datetime.date(2024, 11, 15))
|
|
||||||
|
|
||||||
def test_extends_expiration_date_skips_non_current(self):
|
def test_extends_expiration_date_skips_non_current(self):
|
||||||
"""
|
"""
|
||||||
Tests that the extend_expiration_dates method correctly skips domains
|
Tests that the extend_expiration_dates method correctly skips domains
|
||||||
with an expiration date less than a certain threshold.
|
with an expiration date less than a certain threshold.
|
||||||
"""
|
"""
|
||||||
desired_domain = Domain.objects.filter(name="fake.gov").get()
|
with less_console_noise():
|
||||||
desired_domain.expiration_date = datetime.date(2022, 5, 25)
|
desired_domain = Domain.objects.filter(name="fake.gov").get()
|
||||||
|
desired_domain.expiration_date = date(2022, 5, 25)
|
||||||
# Run the expiration date script
|
# Run the expiration date script
|
||||||
self.run_extend_expiration_dates()
|
self.run_extend_expiration_dates()
|
||||||
|
current_domain = Domain.objects.filter(name="fake.gov").get()
|
||||||
current_domain = Domain.objects.filter(name="fake.gov").get()
|
self.assertEqual(desired_domain, current_domain)
|
||||||
self.assertEqual(desired_domain, current_domain)
|
# Explicitly test the expiration date. The extend_expiration_dates script
|
||||||
|
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
||||||
# Explicitly test the expiration date. The extend_expiration_dates script
|
# should not be affected by the change.
|
||||||
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
self.assertEqual(current_domain.expiration_date, date(2022, 5, 25))
|
||||||
# should not be affected by the change.
|
|
||||||
self.assertEqual(current_domain.expiration_date, datetime.date(2022, 5, 25))
|
|
||||||
|
|
||||||
def test_extends_expiration_date_skips_maximum_date(self):
|
def test_extends_expiration_date_skips_maximum_date(self):
|
||||||
"""
|
"""
|
||||||
Tests that the extend_expiration_dates method correctly skips domains
|
Tests that the extend_expiration_dates method correctly skips domains
|
||||||
with an expiration date more than a certain threshold.
|
with an expiration date more than a certain threshold.
|
||||||
"""
|
"""
|
||||||
desired_domain = Domain.objects.filter(name="fakemaximum.gov").get()
|
with less_console_noise():
|
||||||
desired_domain.expiration_date = datetime.date(2024, 12, 31)
|
desired_domain = Domain.objects.filter(name="fakemaximum.gov").get()
|
||||||
|
desired_domain.expiration_date = date(2024, 12, 31)
|
||||||
|
|
||||||
# Run the expiration date script
|
# Run the expiration date script
|
||||||
self.run_extend_expiration_dates()
|
self.run_extend_expiration_dates()
|
||||||
|
|
||||||
current_domain = Domain.objects.filter(name="fakemaximum.gov").get()
|
current_domain = Domain.objects.filter(name="fakemaximum.gov").get()
|
||||||
self.assertEqual(desired_domain, current_domain)
|
self.assertEqual(desired_domain, current_domain)
|
||||||
|
|
||||||
# Explicitly test the expiration date. The extend_expiration_dates script
|
# Explicitly test the expiration date. The extend_expiration_dates script
|
||||||
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
||||||
# should not be affected by the change.
|
# should not be affected by the change.
|
||||||
self.assertEqual(current_domain.expiration_date, datetime.date(2024, 12, 31))
|
self.assertEqual(current_domain.expiration_date, date(2024, 12, 31))
|
||||||
|
|
||||||
def test_extends_expiration_date_skips_non_ready(self):
|
def test_extends_expiration_date_skips_non_ready(self):
|
||||||
"""
|
"""
|
||||||
Tests that the extend_expiration_dates method correctly skips domains not in the state "ready"
|
Tests that the extend_expiration_dates method correctly skips domains not in the state "ready"
|
||||||
"""
|
"""
|
||||||
desired_domain = Domain.objects.filter(name="fakeneeded.gov").get()
|
with less_console_noise():
|
||||||
desired_domain.expiration_date = datetime.date(2023, 11, 15)
|
desired_domain = Domain.objects.filter(name="fakeneeded.gov").get()
|
||||||
|
desired_domain.expiration_date = date(2023, 11, 15)
|
||||||
|
|
||||||
# Run the expiration date script
|
# Run the expiration date script
|
||||||
self.run_extend_expiration_dates()
|
self.run_extend_expiration_dates()
|
||||||
|
|
||||||
current_domain = Domain.objects.filter(name="fakeneeded.gov").get()
|
current_domain = Domain.objects.filter(name="fakeneeded.gov").get()
|
||||||
self.assertEqual(desired_domain, current_domain)
|
self.assertEqual(desired_domain, current_domain)
|
||||||
|
|
||||||
# Explicitly test the expiration date. The extend_expiration_dates script
|
# Explicitly test the expiration date. The extend_expiration_dates script
|
||||||
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
# will skip all dates less than date(2023, 11, 15), meaning that this domain
|
||||||
# should not be affected by the change.
|
# should not be affected by the change.
|
||||||
self.assertEqual(current_domain.expiration_date, datetime.date(2023, 11, 15))
|
self.assertEqual(current_domain.expiration_date, date(2023, 11, 15))
|
||||||
|
|
||||||
def test_extends_expiration_date_idempotent(self):
|
def test_extends_expiration_date_idempotent(self):
|
||||||
"""
|
"""
|
||||||
|
@ -423,26 +392,21 @@ class TestExtendExpirationDates(MockEppLib):
|
||||||
Verifies that running the method multiple times does not change the expiration date
|
Verifies that running the method multiple times does not change the expiration date
|
||||||
of a domain beyond the initial extension.
|
of a domain beyond the initial extension.
|
||||||
"""
|
"""
|
||||||
desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
with less_console_noise():
|
||||||
desired_domain.expiration_date = datetime.date(2024, 11, 15)
|
desired_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
||||||
|
desired_domain.expiration_date = date(2024, 11, 15)
|
||||||
# Run the expiration date script
|
# Run the expiration date script
|
||||||
self.run_extend_expiration_dates()
|
self.run_extend_expiration_dates()
|
||||||
|
current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
||||||
current_domain = Domain.objects.filter(name="waterbutpurple.gov").get()
|
self.assertEqual(desired_domain, current_domain)
|
||||||
self.assertEqual(desired_domain, current_domain)
|
# Explicitly test the expiration date
|
||||||
|
self.assertEqual(desired_domain.expiration_date, date(2024, 11, 15))
|
||||||
# Explicitly test the expiration date
|
# Run the expiration date script again
|
||||||
self.assertEqual(desired_domain.expiration_date, datetime.date(2024, 11, 15))
|
self.run_extend_expiration_dates()
|
||||||
|
# The old domain shouldn't have changed
|
||||||
# Run the expiration date script again
|
self.assertEqual(desired_domain, current_domain)
|
||||||
self.run_extend_expiration_dates()
|
# Explicitly test the expiration date - should be the same
|
||||||
|
self.assertEqual(desired_domain.expiration_date, date(2024, 11, 15))
|
||||||
# The old domain shouldn't have changed
|
|
||||||
self.assertEqual(desired_domain, current_domain)
|
|
||||||
|
|
||||||
# Explicitly test the expiration date - should be the same
|
|
||||||
self.assertEqual(desired_domain.expiration_date, datetime.date(2024, 11, 15))
|
|
||||||
|
|
||||||
|
|
||||||
class TestDiscloseEmails(MockEppLib):
|
class TestDiscloseEmails(MockEppLib):
|
||||||
|
@ -461,39 +425,41 @@ class TestDiscloseEmails(MockEppLib):
|
||||||
The 'call_command' function from Django's management framework is then used to
|
The 'call_command' function from Django's management framework is then used to
|
||||||
execute the disclose_security_emails command.
|
execute the disclose_security_emails command.
|
||||||
"""
|
"""
|
||||||
with patch(
|
with less_console_noise():
|
||||||
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
with patch(
|
||||||
return_value=True,
|
"registrar.management.commands.utility.terminal_helper.TerminalHelper.query_yes_no_exit", # noqa
|
||||||
):
|
return_value=True,
|
||||||
call_command("disclose_security_emails")
|
):
|
||||||
|
call_command("disclose_security_emails")
|
||||||
|
|
||||||
def test_disclose_security_emails(self):
|
def test_disclose_security_emails(self):
|
||||||
"""
|
"""
|
||||||
Tests that command disclose_security_emails runs successfully with
|
Tests that command disclose_security_emails runs successfully with
|
||||||
appropriate EPP calll to UpdateContact.
|
appropriate EPP calll to UpdateContact.
|
||||||
"""
|
"""
|
||||||
domain, _ = Domain.objects.get_or_create(name="testdisclose.gov", state=Domain.State.READY)
|
with less_console_noise():
|
||||||
expectedSecContact = PublicContact.get_default_security()
|
domain, _ = Domain.objects.get_or_create(name="testdisclose.gov", state=Domain.State.READY)
|
||||||
expectedSecContact.domain = domain
|
expectedSecContact = PublicContact.get_default_security()
|
||||||
expectedSecContact.email = "123@mail.gov"
|
expectedSecContact.domain = domain
|
||||||
# set domain security email to 123@mail.gov instead of default email
|
expectedSecContact.email = "123@mail.gov"
|
||||||
domain.security_contact = expectedSecContact
|
# set domain security email to 123@mail.gov instead of default email
|
||||||
self.run_disclose_security_emails()
|
domain.security_contact = expectedSecContact
|
||||||
|
self.run_disclose_security_emails()
|
||||||
|
|
||||||
# running disclose_security_emails sends EPP call UpdateContact with disclose
|
# running disclose_security_emails sends EPP call UpdateContact with disclose
|
||||||
self.mockedSendFunction.assert_has_calls(
|
self.mockedSendFunction.assert_has_calls(
|
||||||
[
|
[
|
||||||
call(
|
call(
|
||||||
commands.UpdateContact(
|
commands.UpdateContact(
|
||||||
id=domain.security_contact.registry_id,
|
id=domain.security_contact.registry_id,
|
||||||
postal_info=domain._make_epp_contact_postal_info(contact=domain.security_contact),
|
postal_info=domain._make_epp_contact_postal_info(contact=domain.security_contact),
|
||||||
email=domain.security_contact.email,
|
email=domain.security_contact.email,
|
||||||
voice=domain.security_contact.voice,
|
voice=domain.security_contact.voice,
|
||||||
fax=domain.security_contact.fax,
|
fax=domain.security_contact.fax,
|
||||||
auth_info=common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
|
auth_info=common.ContactAuthInfo(pw="2fooBAR123fooBaz"),
|
||||||
disclose=domain._disclose_fields(contact=domain.security_contact),
|
disclose=domain._disclose_fields(contact=domain.security_contact),
|
||||||
),
|
),
|
||||||
cleaned=True,
|
cleaned=True,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -60,127 +60,134 @@ class TestDomainApplication(TestCase):
|
||||||
|
|
||||||
def assertNotRaises(self, exception_type):
|
def assertNotRaises(self, exception_type):
|
||||||
"""Helper method for testing allowed transitions."""
|
"""Helper method for testing allowed transitions."""
|
||||||
return self.assertRaises(Exception, None, exception_type)
|
with less_console_noise():
|
||||||
|
return self.assertRaises(Exception, None, exception_type)
|
||||||
|
|
||||||
def test_empty_create_fails(self):
|
def test_empty_create_fails(self):
|
||||||
"""Can't create a completely empty domain application.
|
"""Can't create a completely empty domain application.
|
||||||
NOTE: something about theexception this test raises messes up with the
|
NOTE: something about theexception this test raises messes up with the
|
||||||
atomic block in a custom tearDown method for the parent test class."""
|
atomic block in a custom tearDown method for the parent test class."""
|
||||||
with self.assertRaisesRegex(IntegrityError, "creator"):
|
with less_console_noise():
|
||||||
DomainApplication.objects.create()
|
with self.assertRaisesRegex(IntegrityError, "creator"):
|
||||||
|
DomainApplication.objects.create()
|
||||||
|
|
||||||
def test_minimal_create(self):
|
def test_minimal_create(self):
|
||||||
"""Can create with just a creator."""
|
"""Can create with just a creator."""
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
application = DomainApplication.objects.create(creator=user)
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED)
|
application = DomainApplication.objects.create(creator=user)
|
||||||
|
self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED)
|
||||||
|
|
||||||
def test_full_create(self):
|
def test_full_create(self):
|
||||||
"""Can create with all fields."""
|
"""Can create with all fields."""
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
contact = Contact.objects.create()
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
com_website, _ = Website.objects.get_or_create(website="igorville.com")
|
contact = Contact.objects.create()
|
||||||
gov_website, _ = Website.objects.get_or_create(website="igorville.gov")
|
com_website, _ = Website.objects.get_or_create(website="igorville.com")
|
||||||
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
gov_website, _ = Website.objects.get_or_create(website="igorville.gov")
|
||||||
application = DomainApplication.objects.create(
|
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
||||||
creator=user,
|
application = DomainApplication.objects.create(
|
||||||
investigator=user,
|
creator=user,
|
||||||
organization_type=DomainApplication.OrganizationChoices.FEDERAL,
|
investigator=user,
|
||||||
federal_type=DomainApplication.BranchChoices.EXECUTIVE,
|
organization_type=DomainApplication.OrganizationChoices.FEDERAL,
|
||||||
is_election_board=False,
|
federal_type=DomainApplication.BranchChoices.EXECUTIVE,
|
||||||
organization_name="Test",
|
is_election_board=False,
|
||||||
address_line1="100 Main St.",
|
organization_name="Test",
|
||||||
address_line2="APT 1A",
|
address_line1="100 Main St.",
|
||||||
state_territory="CA",
|
address_line2="APT 1A",
|
||||||
zipcode="12345-6789",
|
state_territory="CA",
|
||||||
authorizing_official=contact,
|
zipcode="12345-6789",
|
||||||
requested_domain=domain,
|
authorizing_official=contact,
|
||||||
submitter=contact,
|
requested_domain=domain,
|
||||||
purpose="Igorville rules!",
|
submitter=contact,
|
||||||
anything_else="All of Igorville loves the dotgov program.",
|
purpose="Igorville rules!",
|
||||||
is_policy_acknowledged=True,
|
anything_else="All of Igorville loves the dotgov program.",
|
||||||
)
|
is_policy_acknowledged=True,
|
||||||
application.current_websites.add(com_website)
|
)
|
||||||
application.alternative_domains.add(gov_website)
|
application.current_websites.add(com_website)
|
||||||
application.other_contacts.add(contact)
|
application.alternative_domains.add(gov_website)
|
||||||
application.save()
|
application.other_contacts.add(contact)
|
||||||
|
application.save()
|
||||||
|
|
||||||
def test_domain_info(self):
|
def test_domain_info(self):
|
||||||
"""Can create domain info with all fields."""
|
"""Can create domain info with all fields."""
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
contact = Contact.objects.create()
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
contact = Contact.objects.create()
|
||||||
information = DomainInformation.objects.create(
|
domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
||||||
creator=user,
|
information = DomainInformation.objects.create(
|
||||||
organization_type=DomainInformation.OrganizationChoices.FEDERAL,
|
creator=user,
|
||||||
federal_type=DomainInformation.BranchChoices.EXECUTIVE,
|
organization_type=DomainInformation.OrganizationChoices.FEDERAL,
|
||||||
is_election_board=False,
|
federal_type=DomainInformation.BranchChoices.EXECUTIVE,
|
||||||
organization_name="Test",
|
is_election_board=False,
|
||||||
address_line1="100 Main St.",
|
organization_name="Test",
|
||||||
address_line2="APT 1A",
|
address_line1="100 Main St.",
|
||||||
state_territory="CA",
|
address_line2="APT 1A",
|
||||||
zipcode="12345-6789",
|
state_territory="CA",
|
||||||
authorizing_official=contact,
|
zipcode="12345-6789",
|
||||||
submitter=contact,
|
authorizing_official=contact,
|
||||||
purpose="Igorville rules!",
|
submitter=contact,
|
||||||
anything_else="All of Igorville loves the dotgov program.",
|
purpose="Igorville rules!",
|
||||||
is_policy_acknowledged=True,
|
anything_else="All of Igorville loves the dotgov program.",
|
||||||
domain=domain,
|
is_policy_acknowledged=True,
|
||||||
)
|
domain=domain,
|
||||||
information.other_contacts.add(contact)
|
)
|
||||||
information.save()
|
information.other_contacts.add(contact)
|
||||||
self.assertEqual(information.domain.id, domain.id)
|
information.save()
|
||||||
self.assertEqual(information.id, domain.domain_info.id)
|
self.assertEqual(information.domain.id, domain.id)
|
||||||
|
self.assertEqual(information.id, domain.domain_info.id)
|
||||||
|
|
||||||
def test_status_fsm_submit_fail(self):
|
def test_status_fsm_submit_fail(self):
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
application = DomainApplication.objects.create(creator=user)
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
|
application = DomainApplication.objects.create(creator=user)
|
||||||
|
|
||||||
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
# can't submit an application with a null domain name
|
# can't submit an application with a null domain name
|
||||||
application.submit()
|
application.submit()
|
||||||
|
|
||||||
def test_status_fsm_submit_succeed(self):
|
def test_status_fsm_submit_succeed(self):
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
site = DraftDomain.objects.create(name="igorville.gov")
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
application = DomainApplication.objects.create(creator=user, requested_domain=site)
|
site = DraftDomain.objects.create(name="igorville.gov")
|
||||||
|
application = DomainApplication.objects.create(creator=user, requested_domain=site)
|
||||||
|
|
||||||
# no submitter email so this emits a log warning
|
# no submitter email so this emits a log warning
|
||||||
|
|
||||||
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
application.submit()
|
application.submit()
|
||||||
self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED)
|
self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED)
|
||||||
|
|
||||||
def test_submit_sends_email(self):
|
def test_submit_sends_email(self):
|
||||||
"""Create an application and submit it and see if email was sent."""
|
"""Create an application and submit it and see if email was sent."""
|
||||||
user, _ = User.objects.get_or_create(username="testy")
|
with less_console_noise():
|
||||||
contact = Contact.objects.create(email="test@test.gov")
|
user, _ = User.objects.get_or_create(username="testy")
|
||||||
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
contact = Contact.objects.create(email="test@test.gov")
|
||||||
application = DomainApplication.objects.create(
|
domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
|
||||||
creator=user,
|
application = DomainApplication.objects.create(
|
||||||
requested_domain=domain,
|
creator=user,
|
||||||
submitter=contact,
|
requested_domain=domain,
|
||||||
)
|
submitter=contact,
|
||||||
application.save()
|
)
|
||||||
|
application.save()
|
||||||
|
|
||||||
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
|
||||||
with less_console_noise():
|
|
||||||
application.submit()
|
application.submit()
|
||||||
|
|
||||||
# check to see if an email was sent
|
# check to see if an email was sent
|
||||||
self.assertGreater(
|
self.assertGreater(
|
||||||
len(
|
len(
|
||||||
[
|
[
|
||||||
email
|
email
|
||||||
for email in MockSESClient.EMAILS_SENT
|
for email in MockSESClient.EMAILS_SENT
|
||||||
if "test@test.gov" in email["kwargs"]["Destination"]["ToAddresses"]
|
if "test@test.gov" in email["kwargs"]["Destination"]["ToAddresses"]
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_submit_transition_allowed(self):
|
def test_submit_transition_allowed(self):
|
||||||
"""
|
"""
|
||||||
|
@ -268,13 +275,13 @@ class TestDomainApplication(TestCase):
|
||||||
(self.rejected_application, TransitionNotAllowed),
|
(self.rejected_application, TransitionNotAllowed),
|
||||||
(self.ineligible_application, TransitionNotAllowed),
|
(self.ineligible_application, TransitionNotAllowed),
|
||||||
]
|
]
|
||||||
|
with less_console_noise():
|
||||||
for application, exception_type in test_cases:
|
for application, exception_type in test_cases:
|
||||||
with self.subTest(application=application, exception_type=exception_type):
|
with self.subTest(application=application, exception_type=exception_type):
|
||||||
try:
|
try:
|
||||||
application.action_needed()
|
application.action_needed()
|
||||||
except TransitionNotAllowed:
|
except TransitionNotAllowed:
|
||||||
self.fail("TransitionNotAllowed was raised, but it was not expected.")
|
self.fail("TransitionNotAllowed was raised, but it was not expected.")
|
||||||
|
|
||||||
def test_action_needed_transition_not_allowed(self):
|
def test_action_needed_transition_not_allowed(self):
|
||||||
"""
|
"""
|
||||||
|
@ -286,11 +293,11 @@ class TestDomainApplication(TestCase):
|
||||||
(self.action_needed_application, TransitionNotAllowed),
|
(self.action_needed_application, TransitionNotAllowed),
|
||||||
(self.withdrawn_application, TransitionNotAllowed),
|
(self.withdrawn_application, TransitionNotAllowed),
|
||||||
]
|
]
|
||||||
|
with less_console_noise():
|
||||||
for application, exception_type in test_cases:
|
for application, exception_type in test_cases:
|
||||||
with self.subTest(application=application, exception_type=exception_type):
|
with self.subTest(application=application, exception_type=exception_type):
|
||||||
with self.assertRaises(exception_type):
|
with self.assertRaises(exception_type):
|
||||||
application.action_needed()
|
application.action_needed()
|
||||||
|
|
||||||
def test_approved_transition_allowed(self):
|
def test_approved_transition_allowed(self):
|
||||||
"""
|
"""
|
||||||
|
@ -499,25 +506,29 @@ class TestDomainApplication(TestCase):
|
||||||
|
|
||||||
def test_has_rationale_returns_true(self):
|
def test_has_rationale_returns_true(self):
|
||||||
"""has_rationale() returns true when an application has no_other_contacts_rationale"""
|
"""has_rationale() returns true when an application has no_other_contacts_rationale"""
|
||||||
self.started_application.no_other_contacts_rationale = "You talkin' to me?"
|
with less_console_noise():
|
||||||
self.started_application.save()
|
self.started_application.no_other_contacts_rationale = "You talkin' to me?"
|
||||||
self.assertEquals(self.started_application.has_rationale(), True)
|
self.started_application.save()
|
||||||
|
self.assertEquals(self.started_application.has_rationale(), True)
|
||||||
|
|
||||||
def test_has_rationale_returns_false(self):
|
def test_has_rationale_returns_false(self):
|
||||||
"""has_rationale() returns false when an application has no no_other_contacts_rationale"""
|
"""has_rationale() returns false when an application has no no_other_contacts_rationale"""
|
||||||
self.assertEquals(self.started_application.has_rationale(), False)
|
with less_console_noise():
|
||||||
|
self.assertEquals(self.started_application.has_rationale(), False)
|
||||||
|
|
||||||
def test_has_other_contacts_returns_true(self):
|
def test_has_other_contacts_returns_true(self):
|
||||||
"""has_other_contacts() returns true when an application has other_contacts"""
|
"""has_other_contacts() returns true when an application has other_contacts"""
|
||||||
# completed_application has other contacts by default
|
with less_console_noise():
|
||||||
self.assertEquals(self.started_application.has_other_contacts(), True)
|
# completed_application has other contacts by default
|
||||||
|
self.assertEquals(self.started_application.has_other_contacts(), True)
|
||||||
|
|
||||||
def test_has_other_contacts_returns_false(self):
|
def test_has_other_contacts_returns_false(self):
|
||||||
"""has_other_contacts() returns false when an application has no other_contacts"""
|
"""has_other_contacts() returns false when an application has no other_contacts"""
|
||||||
application = completed_application(
|
with less_console_noise():
|
||||||
status=DomainApplication.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False
|
application = completed_application(
|
||||||
)
|
status=DomainApplication.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False
|
||||||
self.assertEquals(application.has_other_contacts(), False)
|
)
|
||||||
|
self.assertEquals(application.has_other_contacts(), False)
|
||||||
|
|
||||||
|
|
||||||
class TestPermissions(TestCase):
|
class TestPermissions(TestCase):
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,7 @@ import boto3_mocking
|
||||||
from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore
|
from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from .common import less_console_noise
|
||||||
|
|
||||||
|
|
||||||
class CsvReportsTest(TestCase):
|
class CsvReportsTest(TestCase):
|
||||||
|
@ -80,41 +81,43 @@ class CsvReportsTest(TestCase):
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_generate_federal_report(self):
|
def test_generate_federal_report(self):
|
||||||
"""Ensures that we correctly generate current-federal.csv"""
|
"""Ensures that we correctly generate current-federal.csv"""
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
fake_open = mock_open()
|
mock_client = MagicMock()
|
||||||
expected_file_content = [
|
fake_open = mock_open()
|
||||||
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
|
expected_file_content = [
|
||||||
call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
|
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
|
||||||
call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
|
call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
|
||||||
]
|
call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
|
||||||
# We don't actually want to write anything for a test case,
|
]
|
||||||
# we just want to verify what is being written.
|
# We don't actually want to write anything for a test case,
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
# we just want to verify what is being written.
|
||||||
with patch("builtins.open", fake_open):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
call_command("generate_current_federal_report", checkpath=False)
|
with patch("builtins.open", fake_open):
|
||||||
content = fake_open()
|
call_command("generate_current_federal_report", checkpath=False)
|
||||||
|
content = fake_open()
|
||||||
|
|
||||||
content.write.assert_has_calls(expected_file_content)
|
content.write.assert_has_calls(expected_file_content)
|
||||||
|
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_generate_full_report(self):
|
def test_generate_full_report(self):
|
||||||
"""Ensures that we correctly generate current-full.csv"""
|
"""Ensures that we correctly generate current-full.csv"""
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
fake_open = mock_open()
|
mock_client = MagicMock()
|
||||||
expected_file_content = [
|
fake_open = mock_open()
|
||||||
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
|
expected_file_content = [
|
||||||
call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
|
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
|
||||||
call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
|
call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"),
|
||||||
call("adomain2.gov,Interstate,,,,, \r\n"),
|
call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"),
|
||||||
]
|
call("adomain2.gov,Interstate,,,,, \r\n"),
|
||||||
# We don't actually want to write anything for a test case,
|
]
|
||||||
# we just want to verify what is being written.
|
# We don't actually want to write anything for a test case,
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
# we just want to verify what is being written.
|
||||||
with patch("builtins.open", fake_open):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
call_command("generate_current_full_report", checkpath=False)
|
with patch("builtins.open", fake_open):
|
||||||
content = fake_open()
|
call_command("generate_current_full_report", checkpath=False)
|
||||||
|
content = fake_open()
|
||||||
|
|
||||||
content.write.assert_has_calls(expected_file_content)
|
content.write.assert_has_calls(expected_file_content)
|
||||||
|
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_not_found_full_report(self):
|
def test_not_found_full_report(self):
|
||||||
|
@ -123,19 +126,20 @@ class CsvReportsTest(TestCase):
|
||||||
def side_effect(Bucket, Key):
|
def side_effect(Bucket, Key):
|
||||||
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
|
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
|
||||||
|
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
mock_client.get_object.side_effect = side_effect
|
mock_client = MagicMock()
|
||||||
|
mock_client.get_object.side_effect = side_effect
|
||||||
|
|
||||||
response = None
|
response = None
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
with patch("boto3.client", return_value=mock_client):
|
with patch("boto3.client", return_value=mock_client):
|
||||||
with self.assertRaises(S3ClientError) as context:
|
with self.assertRaises(S3ClientError) as context:
|
||||||
response = self.client.get("/api/v1/get-report/current-full")
|
response = self.client.get("/api/v1/get-report/current-full")
|
||||||
# Check that the response has status code 500
|
# Check that the response has status code 500
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
|
|
||||||
# Check that we get the right error back from the page
|
# Check that we get the right error back from the page
|
||||||
self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
|
self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
|
||||||
|
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_not_found_federal_report(self):
|
def test_not_found_federal_report(self):
|
||||||
|
@ -144,83 +148,86 @@ class CsvReportsTest(TestCase):
|
||||||
def side_effect(Bucket, Key):
|
def side_effect(Bucket, Key):
|
||||||
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
|
raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object")
|
||||||
|
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
mock_client.get_object.side_effect = side_effect
|
mock_client = MagicMock()
|
||||||
|
mock_client.get_object.side_effect = side_effect
|
||||||
|
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
with patch("boto3.client", return_value=mock_client):
|
with patch("boto3.client", return_value=mock_client):
|
||||||
with self.assertRaises(S3ClientError) as context:
|
with self.assertRaises(S3ClientError) as context:
|
||||||
response = self.client.get("/api/v1/get-report/current-federal")
|
response = self.client.get("/api/v1/get-report/current-federal")
|
||||||
# Check that the response has status code 500
|
# Check that the response has status code 500
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
|
|
||||||
# Check that we get the right error back from the page
|
# Check that we get the right error back from the page
|
||||||
self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
|
self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR)
|
||||||
|
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_load_federal_report(self):
|
def test_load_federal_report(self):
|
||||||
"""Tests the get_current_federal api endpoint"""
|
"""Tests the get_current_federal api endpoint"""
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
mock_client_instance = mock_client.return_value
|
mock_client = MagicMock()
|
||||||
|
mock_client_instance = mock_client.return_value
|
||||||
|
|
||||||
with open("registrar/tests/data/fake_current_federal.csv", "r") as file:
|
with open("registrar/tests/data/fake_current_federal.csv", "r") as file:
|
||||||
file_content = file.read()
|
file_content = file.read()
|
||||||
|
|
||||||
# Mock a recieved file
|
# Mock a recieved file
|
||||||
mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
|
mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
request = self.factory.get("/fake-path")
|
request = self.factory.get("/fake-path")
|
||||||
response = get_current_federal(request)
|
response = get_current_federal(request)
|
||||||
|
|
||||||
# Check that we are sending the correct calls.
|
# Check that we are sending the correct calls.
|
||||||
# Ensures that we are decoding the file content recieved from AWS.
|
# Ensures that we are decoding the file content recieved from AWS.
|
||||||
expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-federal.csv")]
|
expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-federal.csv")]
|
||||||
mock_client_instance.assert_has_calls(expected_call)
|
mock_client_instance.assert_has_calls(expected_call)
|
||||||
|
|
||||||
# Check that the response has status code 200
|
# Check that the response has status code 200
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
# Check that the response contains what we expect
|
# Check that the response contains what we expect
|
||||||
expected_file_content = (
|
expected_file_content = (
|
||||||
"Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
|
"Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
|
||||||
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
|
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
|
||||||
"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,"
|
"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,"
|
||||||
).encode()
|
).encode()
|
||||||
|
|
||||||
self.assertEqual(expected_file_content, response.content)
|
self.assertEqual(expected_file_content, response.content)
|
||||||
|
|
||||||
@boto3_mocking.patching
|
@boto3_mocking.patching
|
||||||
def test_load_full_report(self):
|
def test_load_full_report(self):
|
||||||
"""Tests the current-federal api link"""
|
"""Tests the current-federal api link"""
|
||||||
mock_client = MagicMock()
|
with less_console_noise():
|
||||||
mock_client_instance = mock_client.return_value
|
mock_client = MagicMock()
|
||||||
|
mock_client_instance = mock_client.return_value
|
||||||
|
|
||||||
with open("registrar/tests/data/fake_current_full.csv", "r") as file:
|
with open("registrar/tests/data/fake_current_full.csv", "r") as file:
|
||||||
file_content = file.read()
|
file_content = file.read()
|
||||||
|
|
||||||
# Mock a recieved file
|
# Mock a recieved file
|
||||||
mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
|
mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())}
|
||||||
with boto3_mocking.clients.handler_for("s3", mock_client):
|
with boto3_mocking.clients.handler_for("s3", mock_client):
|
||||||
request = self.factory.get("/fake-path")
|
request = self.factory.get("/fake-path")
|
||||||
response = get_current_full(request)
|
response = get_current_full(request)
|
||||||
|
|
||||||
# Check that we are sending the correct calls.
|
# Check that we are sending the correct calls.
|
||||||
# Ensures that we are decoding the file content recieved from AWS.
|
# Ensures that we are decoding the file content recieved from AWS.
|
||||||
expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-full.csv")]
|
expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-full.csv")]
|
||||||
mock_client_instance.assert_has_calls(expected_call)
|
mock_client_instance.assert_has_calls(expected_call)
|
||||||
|
|
||||||
# Check that the response has status code 200
|
# Check that the response has status code 200
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
# Check that the response contains what we expect
|
# Check that the response contains what we expect
|
||||||
expected_file_content = (
|
expected_file_content = (
|
||||||
"Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
|
"Domain name,Domain type,Agency,Organization name,City,State,Security contact email\n"
|
||||||
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
|
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n"
|
||||||
"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n"
|
"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n"
|
||||||
"adomain2.gov,Interstate,,,,,"
|
"adomain2.gov,Interstate,,,,,"
|
||||||
).encode()
|
).encode()
|
||||||
|
|
||||||
self.assertEqual(expected_file_content, response.content)
|
self.assertEqual(expected_file_content, response.content)
|
||||||
|
|
||||||
|
|
||||||
class ExportDataTest(MockEppLib):
|
class ExportDataTest(MockEppLib):
|
||||||
|
@ -339,192 +346,170 @@ class ExportDataTest(MockEppLib):
|
||||||
def test_export_domains_to_writer_security_emails(self):
|
def test_export_domains_to_writer_security_emails(self):
|
||||||
"""Test that export_domains_to_writer returns the
|
"""Test that export_domains_to_writer returns the
|
||||||
expected security email"""
|
expected security email"""
|
||||||
|
with less_console_noise():
|
||||||
# Add security email information
|
# Add security email information
|
||||||
self.domain_1.name = "defaultsecurity.gov"
|
self.domain_1.name = "defaultsecurity.gov"
|
||||||
self.domain_1.save()
|
self.domain_1.save()
|
||||||
|
# Invoke setter
|
||||||
# Invoke setter
|
self.domain_1.security_contact
|
||||||
self.domain_1.security_contact
|
# Invoke setter
|
||||||
|
self.domain_2.security_contact
|
||||||
# Invoke setter
|
# Invoke setter
|
||||||
self.domain_2.security_contact
|
self.domain_3.security_contact
|
||||||
|
# Create a CSV file in memory
|
||||||
# Invoke setter
|
csv_file = StringIO()
|
||||||
self.domain_3.security_contact
|
writer = csv.writer(csv_file)
|
||||||
|
# Define columns, sort fields, and filter condition
|
||||||
# Create a CSV file in memory
|
columns = [
|
||||||
csv_file = StringIO()
|
"Domain name",
|
||||||
writer = csv.writer(csv_file)
|
"Domain type",
|
||||||
|
"Agency",
|
||||||
# Define columns, sort fields, and filter condition
|
"Organization name",
|
||||||
columns = [
|
"City",
|
||||||
"Domain name",
|
"State",
|
||||||
"Domain type",
|
"AO",
|
||||||
"Agency",
|
"AO email",
|
||||||
"Organization name",
|
"Security contact email",
|
||||||
"City",
|
"Status",
|
||||||
"State",
|
"Expiration date",
|
||||||
"AO",
|
]
|
||||||
"AO email",
|
sort_fields = ["domain__name"]
|
||||||
"Security contact email",
|
filter_condition = {
|
||||||
"Status",
|
"domain__state__in": [
|
||||||
"Expiration date",
|
Domain.State.READY,
|
||||||
]
|
Domain.State.DNS_NEEDED,
|
||||||
sort_fields = ["domain__name"]
|
Domain.State.ON_HOLD,
|
||||||
filter_condition = {
|
],
|
||||||
"domain__state__in": [
|
}
|
||||||
Domain.State.READY,
|
self.maxDiff = None
|
||||||
Domain.State.DNS_NEEDED,
|
# Call the export functions
|
||||||
Domain.State.ON_HOLD,
|
write_header(writer, columns)
|
||||||
],
|
write_body(writer, columns, sort_fields, filter_condition)
|
||||||
}
|
# Reset the CSV file's position to the beginning
|
||||||
|
csv_file.seek(0)
|
||||||
self.maxDiff = None
|
# Read the content into a variable
|
||||||
# Call the export functions
|
csv_content = csv_file.read()
|
||||||
write_header(writer, columns)
|
# We expect READY domains,
|
||||||
write_body(writer, columns, sort_fields, filter_condition)
|
# sorted alphabetially by domain name
|
||||||
|
expected_content = (
|
||||||
# Reset the CSV file's position to the beginning
|
"Domain name,Domain type,Agency,Organization name,City,State,AO,"
|
||||||
csv_file.seek(0)
|
"AO email,Security contact email,Status,Expiration date\n"
|
||||||
|
"adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
|
||||||
# Read the content into a variable
|
"adomain2.gov,Interstate,(blank),Dns needed\n"
|
||||||
csv_content = csv_file.read()
|
"ddomain3.gov,Federal,Armed Forces Retirement Home,123@mail.gov,On hold,2023-05-25\n"
|
||||||
|
"defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready"
|
||||||
# We expect READY domains,
|
)
|
||||||
# sorted alphabetially by domain name
|
# Normalize line endings and remove commas,
|
||||||
expected_content = (
|
# spaces and leading/trailing whitespace
|
||||||
"Domain name,Domain type,Agency,Organization name,City,State,AO,"
|
csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
|
||||||
"AO email,Security contact email,Status,Expiration date\n"
|
expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
|
||||||
"adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
|
self.assertEqual(csv_content, expected_content)
|
||||||
"adomain2.gov,Interstate,(blank),Dns needed\n"
|
|
||||||
"ddomain3.gov,Federal,Armed Forces Retirement Home,123@mail.gov,On hold,2023-05-25\n"
|
|
||||||
"defaultsecurity.gov,Federal - Executive,World War I Centennial Commission,(blank),Ready"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 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_body(self):
|
def test_write_body(self):
|
||||||
"""Test that write_body returns the
|
"""Test that write_body returns the
|
||||||
existing domain, test that sort by domain name works,
|
existing domain, test that sort by domain name works,
|
||||||
test that filter works"""
|
test that filter works"""
|
||||||
# Create a CSV file in memory
|
with less_console_noise():
|
||||||
csv_file = StringIO()
|
# Create a CSV file in memory
|
||||||
writer = csv.writer(csv_file)
|
csv_file = StringIO()
|
||||||
|
writer = csv.writer(csv_file)
|
||||||
|
|
||||||
# Define columns, sort fields, and filter condition
|
# Define columns, sort fields, and filter condition
|
||||||
columns = [
|
columns = [
|
||||||
"Domain name",
|
"Domain name",
|
||||||
"Domain type",
|
"Domain type",
|
||||||
"Agency",
|
"Agency",
|
||||||
"Organization name",
|
"Organization name",
|
||||||
"City",
|
"City",
|
||||||
"State",
|
"State",
|
||||||
"AO",
|
"AO",
|
||||||
"AO email",
|
"AO email",
|
||||||
"Submitter",
|
"Submitter",
|
||||||
"Submitter title",
|
"Submitter title",
|
||||||
"Submitter email",
|
"Submitter email",
|
||||||
"Submitter phone",
|
"Submitter phone",
|
||||||
"Security contact email",
|
"Security contact email",
|
||||||
"Status",
|
"Status",
|
||||||
]
|
]
|
||||||
sort_fields = ["domain__name"]
|
sort_fields = ["domain__name"]
|
||||||
filter_condition = {
|
filter_condition = {
|
||||||
"domain__state__in": [
|
"domain__state__in": [
|
||||||
Domain.State.READY,
|
Domain.State.READY,
|
||||||
Domain.State.DNS_NEEDED,
|
Domain.State.DNS_NEEDED,
|
||||||
Domain.State.ON_HOLD,
|
Domain.State.ON_HOLD,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
# Call the export functions
|
||||||
# Call the export functions
|
write_header(writer, columns)
|
||||||
write_header(writer, columns)
|
write_body(writer, columns, sort_fields, filter_condition)
|
||||||
write_body(writer, columns, sort_fields, filter_condition)
|
# Reset the CSV file's position to the beginning
|
||||||
|
csv_file.seek(0)
|
||||||
# Reset the CSV file's position to the beginning
|
# Read the content into a variable
|
||||||
csv_file.seek(0)
|
csv_content = csv_file.read()
|
||||||
|
# We expect READY domains,
|
||||||
# Read the content into a variable
|
# sorted alphabetially by domain name
|
||||||
csv_content = csv_file.read()
|
expected_content = (
|
||||||
|
"Domain name,Domain type,Agency,Organization name,City,State,AO,"
|
||||||
# We expect READY domains,
|
"AO email,Submitter,Submitter title,Submitter email,Submitter phone,"
|
||||||
# sorted alphabetially by domain name
|
"Security contact email,Status\n"
|
||||||
expected_content = (
|
"adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
|
||||||
"Domain name,Domain type,Agency,Organization name,City,State,AO,"
|
"adomain2.gov,Interstate,Dns needed\n"
|
||||||
"AO email,Submitter,Submitter title,Submitter email,Submitter phone,"
|
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,Ready\n"
|
||||||
"Security contact email,Status\n"
|
"ddomain3.gov,Federal,Armed Forces Retirement Home,On hold\n"
|
||||||
"adomain10.gov,Federal,Armed Forces Retirement Home,Ready\n"
|
)
|
||||||
"adomain2.gov,Interstate,Dns needed\n"
|
# Normalize line endings and remove commas,
|
||||||
"cdomain1.gov,Federal - Executive,World War I Centennial Commission,Ready\n"
|
# spaces and leading/trailing whitespace
|
||||||
"ddomain3.gov,Federal,Armed Forces Retirement Home,On hold\n"
|
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)
|
||||||
# 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_body_additional(self):
|
def test_write_body_additional(self):
|
||||||
"""An additional test for filters and multi-column sort"""
|
"""An additional test for filters and multi-column sort"""
|
||||||
# Create a CSV file in memory
|
with less_console_noise():
|
||||||
csv_file = StringIO()
|
# Create a CSV file in memory
|
||||||
writer = csv.writer(csv_file)
|
csv_file = StringIO()
|
||||||
|
writer = csv.writer(csv_file)
|
||||||
# Define columns, sort fields, and filter condition
|
# Define columns, sort fields, and filter condition
|
||||||
columns = [
|
columns = [
|
||||||
"Domain name",
|
"Domain name",
|
||||||
"Domain type",
|
"Domain type",
|
||||||
"Agency",
|
"Agency",
|
||||||
"Organization name",
|
"Organization name",
|
||||||
"City",
|
"City",
|
||||||
"State",
|
"State",
|
||||||
"Security contact email",
|
"Security contact email",
|
||||||
]
|
]
|
||||||
sort_fields = ["domain__name", "federal_agency", "organization_type"]
|
sort_fields = ["domain__name", "federal_agency", "organization_type"]
|
||||||
filter_condition = {
|
filter_condition = {
|
||||||
"organization_type__icontains": "federal",
|
"organization_type__icontains": "federal",
|
||||||
"domain__state__in": [
|
"domain__state__in": [
|
||||||
Domain.State.READY,
|
Domain.State.READY,
|
||||||
Domain.State.DNS_NEEDED,
|
Domain.State.DNS_NEEDED,
|
||||||
Domain.State.ON_HOLD,
|
Domain.State.ON_HOLD,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
# Call the export functions
|
||||||
# Call the export functions
|
write_header(writer, columns)
|
||||||
write_header(writer, columns)
|
write_body(writer, columns, sort_fields, filter_condition)
|
||||||
write_body(writer, columns, sort_fields, filter_condition)
|
# Reset the CSV file's position to the beginning
|
||||||
|
csv_file.seek(0)
|
||||||
# Reset the CSV file's position to the beginning
|
# Read the content into a variable
|
||||||
csv_file.seek(0)
|
csv_content = csv_file.read()
|
||||||
|
# We expect READY domains,
|
||||||
# Read the content into a variable
|
# federal only
|
||||||
csv_content = csv_file.read()
|
# sorted alphabetially by domain name
|
||||||
|
expected_content = (
|
||||||
# We expect READY domains,
|
"Domain name,Domain type,Agency,Organization name,City,"
|
||||||
# federal only
|
"State,Security contact email\n"
|
||||||
# sorted alphabetially by domain name
|
"adomain10.gov,Federal,Armed Forces Retirement Home\n"
|
||||||
expected_content = (
|
"cdomain1.gov,Federal - Executive,World War I Centennial Commission\n"
|
||||||
"Domain name,Domain type,Agency,Organization name,City,"
|
"ddomain3.gov,Federal,Armed Forces Retirement Home\n"
|
||||||
"State,Security contact email\n"
|
)
|
||||||
"adomain10.gov,Federal,Armed Forces Retirement Home\n"
|
# Normalize line endings and remove commas,
|
||||||
"cdomain1.gov,Federal - Executive,World War I Centennial Commission\n"
|
# spaces and leading/trailing whitespace
|
||||||
"ddomain3.gov,Federal,Armed Forces Retirement Home\n"
|
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)
|
||||||
# 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_body_with_date_filter_pulls_domains_in_range(self):
|
def test_write_body_with_date_filter_pulls_domains_in_range(self):
|
||||||
"""Test that domains that are
|
"""Test that domains that are
|
||||||
|
@ -538,88 +523,88 @@ class ExportDataTest(MockEppLib):
|
||||||
which are hard to mock.
|
which are hard to mock.
|
||||||
|
|
||||||
TODO: Simplify is created_at is not needed for the report."""
|
TODO: Simplify is created_at is not needed for the report."""
|
||||||
|
with less_console_noise():
|
||||||
|
# Create a CSV file in memory
|
||||||
|
csv_file = StringIO()
|
||||||
|
writer = csv.writer(csv_file)
|
||||||
|
# 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()).
|
||||||
|
end_date = timezone.make_aware(datetime.combine(date.today() + timedelta(days=2), datetime.min.time()))
|
||||||
|
start_date = timezone.make_aware(datetime.combine(date.today() - timedelta(days=2), datetime.min.time()))
|
||||||
|
|
||||||
# Create a CSV file in memory
|
# Define columns, sort fields, and filter condition
|
||||||
csv_file = StringIO()
|
columns = [
|
||||||
writer = csv.writer(csv_file)
|
"Domain name",
|
||||||
# We use timezone.make_aware to sync to server time a datetime object with the current date (using date.today())
|
"Domain type",
|
||||||
# and a specific time (using datetime.min.time()).
|
"Agency",
|
||||||
end_date = timezone.make_aware(datetime.combine(date.today() + timedelta(days=2), datetime.min.time()))
|
"Organization name",
|
||||||
start_date = timezone.make_aware(datetime.combine(date.today() - timedelta(days=2), datetime.min.time()))
|
"City",
|
||||||
|
"State",
|
||||||
|
"Status",
|
||||||
|
"Expiration date",
|
||||||
|
]
|
||||||
|
sort_fields = [
|
||||||
|
"created_at",
|
||||||
|
"domain__name",
|
||||||
|
]
|
||||||
|
sort_fields_for_deleted_domains = [
|
||||||
|
"domain__deleted",
|
||||||
|
"domain__name",
|
||||||
|
]
|
||||||
|
filter_condition = {
|
||||||
|
"domain__state__in": [
|
||||||
|
Domain.State.READY,
|
||||||
|
],
|
||||||
|
"domain__first_ready__lte": end_date,
|
||||||
|
"domain__first_ready__gte": start_date,
|
||||||
|
}
|
||||||
|
filter_conditions_for_deleted_domains = {
|
||||||
|
"domain__state__in": [
|
||||||
|
Domain.State.DELETED,
|
||||||
|
],
|
||||||
|
"domain__deleted__lte": end_date,
|
||||||
|
"domain__deleted__gte": start_date,
|
||||||
|
}
|
||||||
|
|
||||||
# Define columns, sort fields, and filter condition
|
# Call the export functions
|
||||||
columns = [
|
write_header(writer, columns)
|
||||||
"Domain name",
|
write_body(
|
||||||
"Domain type",
|
writer,
|
||||||
"Agency",
|
columns,
|
||||||
"Organization name",
|
sort_fields,
|
||||||
"City",
|
filter_condition,
|
||||||
"State",
|
)
|
||||||
"Status",
|
write_body(
|
||||||
"Expiration date",
|
writer,
|
||||||
]
|
columns,
|
||||||
sort_fields = [
|
sort_fields_for_deleted_domains,
|
||||||
"created_at",
|
filter_conditions_for_deleted_domains,
|
||||||
"domain__name",
|
)
|
||||||
]
|
|
||||||
sort_fields_for_deleted_domains = [
|
|
||||||
"domain__deleted",
|
|
||||||
"domain__name",
|
|
||||||
]
|
|
||||||
filter_condition = {
|
|
||||||
"domain__state__in": [
|
|
||||||
Domain.State.READY,
|
|
||||||
],
|
|
||||||
"domain__first_ready__lte": end_date,
|
|
||||||
"domain__first_ready__gte": start_date,
|
|
||||||
}
|
|
||||||
filter_conditions_for_deleted_domains = {
|
|
||||||
"domain__state__in": [
|
|
||||||
Domain.State.DELETED,
|
|
||||||
],
|
|
||||||
"domain__deleted__lte": end_date,
|
|
||||||
"domain__deleted__gte": start_date,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Call the export functions
|
# Reset the CSV file's position to the beginning
|
||||||
write_header(writer, columns)
|
csv_file.seek(0)
|
||||||
write_body(
|
|
||||||
writer,
|
|
||||||
columns,
|
|
||||||
sort_fields,
|
|
||||||
filter_condition,
|
|
||||||
)
|
|
||||||
write_body(
|
|
||||||
writer,
|
|
||||||
columns,
|
|
||||||
sort_fields_for_deleted_domains,
|
|
||||||
filter_conditions_for_deleted_domains,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Reset the CSV file's position to the beginning
|
# Read the content into a variable
|
||||||
csv_file.seek(0)
|
csv_content = csv_file.read()
|
||||||
|
|
||||||
# Read the content into a variable
|
# We expect READY domains first, created between today-2 and today+2, sorted by created_at then name
|
||||||
csv_content = csv_file.read()
|
# and DELETED domains deleted between today-2 and today+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"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
# We expect READY domains first, created between today-2 and today+2, sorted by created_at then name
|
# Normalize line endings and remove commas,
|
||||||
# and DELETED domains deleted between today-2 and today+2, sorted by deleted then name
|
# spaces and leading/trailing whitespace
|
||||||
expected_content = (
|
csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
|
||||||
"Domain name,Domain type,Agency,Organization name,City,"
|
expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
|
||||||
"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"
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Normalize line endings and remove commas,
|
self.assertEqual(csv_content, expected_content)
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
class HelperFunctions(TestCase):
|
class HelperFunctions(TestCase):
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2199
src/registrar/tests/test_views_application.py
Normal file
2199
src/registrar/tests/test_views_application.py
Normal file
File diff suppressed because it is too large
Load diff
1436
src/registrar/tests/test_views_domain.py
Normal file
1436
src/registrar/tests/test_views_domain.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,7 @@ from django.db.models import F, Value, CharField
|
||||||
from django.db.models.functions import Concat, Coalesce
|
from django.db.models.functions import Concat, Coalesce
|
||||||
|
|
||||||
from registrar.models.public_contact import PublicContact
|
from registrar.models.public_contact import PublicContact
|
||||||
|
from registrar.utility.enums import DefaultEmail
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None
|
||||||
security_email = _email if _email is not None else " "
|
security_email = _email if _email is not None else " "
|
||||||
|
|
||||||
# These are default emails that should not be displayed in the csv report
|
# These are default emails that should not be displayed in the csv report
|
||||||
invalid_emails = {"registrar@dotgov.gov", "dotgov@cisa.dhs.gov"}
|
invalid_emails = {DefaultEmail.LEGACY_DEFAULT.value, DefaultEmail.PUBLIC_CONTACT_DEFAULT.value}
|
||||||
if security_email.lower() in invalid_emails:
|
if security_email.lower() in invalid_emails:
|
||||||
security_email = "(blank)"
|
security_email = "(blank)"
|
||||||
|
|
||||||
|
|
|
@ -26,3 +26,15 @@ class LogCode(Enum):
|
||||||
INFO = 3
|
INFO = 3
|
||||||
DEBUG = 4
|
DEBUG = 4
|
||||||
DEFAULT = 5
|
DEFAULT = 5
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultEmail(Enum):
|
||||||
|
"""Stores the string values of default emails
|
||||||
|
|
||||||
|
Overview of emails:
|
||||||
|
- PUBLIC_CONTACT_DEFAULT: "dotgov@cisa.dhs.gov"
|
||||||
|
- LEGACY_DEFAULT: "registrar@dotgov.gov"
|
||||||
|
"""
|
||||||
|
|
||||||
|
PUBLIC_CONTACT_DEFAULT = "dotgov@cisa.dhs.gov"
|
||||||
|
LEGACY_DEFAULT = "registrar@dotgov.gov"
|
||||||
|
|
|
@ -22,6 +22,7 @@ from registrar.models import (
|
||||||
UserDomainRole,
|
UserDomainRole,
|
||||||
)
|
)
|
||||||
from registrar.models.public_contact import PublicContact
|
from registrar.models.public_contact import PublicContact
|
||||||
|
from registrar.utility.enums import DefaultEmail
|
||||||
from registrar.utility.errors import (
|
from registrar.utility.errors import (
|
||||||
GenericError,
|
GenericError,
|
||||||
GenericErrorCodes,
|
GenericErrorCodes,
|
||||||
|
@ -142,11 +143,12 @@ class DomainView(DomainBaseView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
default_email = self.object.get_default_security_contact().email
|
default_emails = [DefaultEmail.PUBLIC_CONTACT_DEFAULT.value, DefaultEmail.LEGACY_DEFAULT.value]
|
||||||
context["default_security_email"] = default_email
|
|
||||||
|
context["hidden_security_emails"] = default_emails
|
||||||
|
|
||||||
security_email = self.object.get_security_email()
|
security_email = self.object.get_security_email()
|
||||||
if security_email is None or security_email == default_email:
|
if security_email is None or security_email in default_emails:
|
||||||
context["security_email"] = None
|
context["security_email"] = None
|
||||||
return context
|
return context
|
||||||
context["security_email"] = security_email
|
context["security_email"] = security_email
|
||||||
|
@ -570,7 +572,7 @@ class DomainSecurityEmailView(DomainFormBaseView):
|
||||||
initial = super().get_initial()
|
initial = super().get_initial()
|
||||||
security_contact = self.object.security_contact
|
security_contact = self.object.security_contact
|
||||||
|
|
||||||
invalid_emails = ["dotgov@cisa.dhs.gov", "registrar@dotgov.gov"]
|
invalid_emails = [DefaultEmail.PUBLIC_CONTACT_DEFAULT.value, DefaultEmail.LEGACY_DEFAULT.value]
|
||||||
if security_contact is None or security_contact.email in invalid_emails:
|
if security_contact is None or security_contact.email in invalid_emails:
|
||||||
initial["security_email"] = None
|
initial["security_email"] = None
|
||||||
return initial
|
return initial
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue