1. from django.apps import apps
    
  2. from django.contrib.auth import authenticate, signals
    
  3. from django.contrib.auth.models import User
    
  4. from django.core.exceptions import FieldDoesNotExist
    
  5. from django.test import TestCase, override_settings
    
  6. from django.test.client import RequestFactory
    
  7. 
    
  8. from .models import MinimalUser, UserWithDisabledLastLoginField
    
  9. 
    
  10. 
    
  11. @override_settings(ROOT_URLCONF="auth_tests.urls")
    
  12. class SignalTestCase(TestCase):
    
  13.     @classmethod
    
  14.     def setUpTestData(cls):
    
  15.         cls.u1 = User.objects.create_user(username="testclient", password="password")
    
  16.         cls.u3 = User.objects.create_user(username="staff", password="password")
    
  17. 
    
  18.     def listener_login(self, user, **kwargs):
    
  19.         self.logged_in.append(user)
    
  20. 
    
  21.     def listener_logout(self, user, **kwargs):
    
  22.         self.logged_out.append(user)
    
  23. 
    
  24.     def listener_login_failed(self, sender, **kwargs):
    
  25.         self.login_failed.append(kwargs)
    
  26. 
    
  27.     def setUp(self):
    
  28.         """Set up the listeners and reset the logged in/logged out counters"""
    
  29.         self.logged_in = []
    
  30.         self.logged_out = []
    
  31.         self.login_failed = []
    
  32.         signals.user_logged_in.connect(self.listener_login)
    
  33.         signals.user_logged_out.connect(self.listener_logout)
    
  34.         signals.user_login_failed.connect(self.listener_login_failed)
    
  35. 
    
  36.     def tearDown(self):
    
  37.         """Disconnect the listeners"""
    
  38.         signals.user_logged_in.disconnect(self.listener_login)
    
  39.         signals.user_logged_out.disconnect(self.listener_logout)
    
  40.         signals.user_login_failed.disconnect(self.listener_login_failed)
    
  41. 
    
  42.     def test_login(self):
    
  43.         # Only a successful login will trigger the success signal.
    
  44.         self.client.login(username="testclient", password="bad")
    
  45.         self.assertEqual(len(self.logged_in), 0)
    
  46.         self.assertEqual(len(self.login_failed), 1)
    
  47.         self.assertEqual(self.login_failed[0]["credentials"]["username"], "testclient")
    
  48.         # verify the password is cleansed
    
  49.         self.assertIn("***", self.login_failed[0]["credentials"]["password"])
    
  50.         self.assertIn("request", self.login_failed[0])
    
  51. 
    
  52.         # Like this:
    
  53.         self.client.login(username="testclient", password="password")
    
  54.         self.assertEqual(len(self.logged_in), 1)
    
  55.         self.assertEqual(self.logged_in[0].username, "testclient")
    
  56. 
    
  57.         # Ensure there were no more failures.
    
  58.         self.assertEqual(len(self.login_failed), 1)
    
  59. 
    
  60.     def test_logout_anonymous(self):
    
  61.         # The log_out function will still trigger the signal for anonymous
    
  62.         # users.
    
  63.         self.client.post("/logout/next_page/")
    
  64.         self.assertEqual(len(self.logged_out), 1)
    
  65.         self.assertIsNone(self.logged_out[0])
    
  66. 
    
  67.     def test_logout(self):
    
  68.         self.client.login(username="testclient", password="password")
    
  69.         self.client.post("/logout/next_page/")
    
  70.         self.assertEqual(len(self.logged_out), 1)
    
  71.         self.assertEqual(self.logged_out[0].username, "testclient")
    
  72. 
    
  73.     def test_update_last_login(self):
    
  74.         """Only `last_login` is updated in `update_last_login`"""
    
  75.         user = self.u3
    
  76.         old_last_login = user.last_login
    
  77. 
    
  78.         user.username = "This username shouldn't get saved"
    
  79.         request = RequestFactory().get("/login")
    
  80.         signals.user_logged_in.send(sender=user.__class__, request=request, user=user)
    
  81.         user = User.objects.get(pk=user.pk)
    
  82.         self.assertEqual(user.username, "staff")
    
  83.         self.assertNotEqual(user.last_login, old_last_login)
    
  84. 
    
  85.     def test_failed_login_without_request(self):
    
  86.         authenticate(username="testclient", password="bad")
    
  87.         self.assertIsNone(self.login_failed[0]["request"])
    
  88. 
    
  89.     def test_login_with_custom_user_without_last_login_field(self):
    
  90.         """
    
  91.         The user_logged_in signal is only registered if the user model has a
    
  92.         last_login field.
    
  93.         """
    
  94.         last_login_receivers = signals.user_logged_in.receivers
    
  95.         try:
    
  96.             signals.user_logged_in.receivers = []
    
  97.             with self.assertRaises(FieldDoesNotExist):
    
  98.                 MinimalUser._meta.get_field("last_login")
    
  99.             with self.settings(AUTH_USER_MODEL="auth_tests.MinimalUser"):
    
  100.                 apps.get_app_config("auth").ready()
    
  101.             self.assertEqual(signals.user_logged_in.receivers, [])
    
  102. 
    
  103.             # last_login is a property whose value is None.
    
  104.             self.assertIsNone(UserWithDisabledLastLoginField().last_login)
    
  105.             with self.settings(
    
  106.                 AUTH_USER_MODEL="auth_tests.UserWithDisabledLastLoginField"
    
  107.             ):
    
  108.                 apps.get_app_config("auth").ready()
    
  109.             self.assertEqual(signals.user_logged_in.receivers, [])
    
  110. 
    
  111.             with self.settings(AUTH_USER_MODEL="auth.User"):
    
  112.                 apps.get_app_config("auth").ready()
    
  113.             self.assertEqual(len(signals.user_logged_in.receivers), 1)
    
  114.         finally:
    
  115.             signals.user_logged_in.receivers = last_login_receivers