set up the listeners and reset the logged inlogged out counters self loggedin self loggedout self loginfailed signals userloggedin connectself listenerlogin signals userloggedout connectself listenerlogout signals userloginfailed connectself listenerloginfailed def teardownself only a successful login will trigger the success signal verify the password is cleansed like this ensure there were no more failures the logout function will still trigger the signal for anonymous users only lastlogin is updated in updatelastlogin user self u3 oldlastlogin user lastlogin user username this username shouldn t get saved request requestfactory getlogin signals userloggedin sendsenderuser class requestrequest useruser user user objects getpkuser pk self assertequaluser username staff self assertnotequaluser lastlogin oldlastlogin def testfailedloginwithoutrequestself authenticateusernametestclient passwordbad self assertisnoneself loginfailed0request def testloginwithcustomuserwithoutlastloginfieldself lastloginreceivers signals userloggedin receivers try signals userloggedin receivers with self assertraisesfielddoesnotexist minimaluser meta getfieldlastlogin with self settingsauthusermodelauthtests minimaluser apps getappconfigauth ready self assertequalsignals userloggedin receivers lastlogin is a property whose value is none self assertisnoneuserwithdisabledlastloginfield lastlogin with self settings authusermodelauthtests userwithdisabledlastloginfield apps getappconfigauth ready self assertequalsignals userloggedin receivers with self settingsauthusermodelauth user apps getappconfigauth ready self assertequallensignals userloggedin receivers 1 finally signals userloggedin receivers lastloginreceivers set up the listeners and reset the logged in logged out counters disconnect the listeners only a successful login will trigger the success signal verify the password is cleansed like this ensure there were no more failures the log_out function will still trigger the signal for anonymous users only last_login is updated in update_last_login the user_logged_in signal is only registered if the user model has a last_login field last_login is a property whose value is none
from django.apps import apps
from django.contrib.auth import authenticate, signals
from django.contrib.auth.models import User
from django.core.exceptions import FieldDoesNotExist
from django.test import TestCase, override_settings
from django.test.client import RequestFactory

from .models import MinimalUser, UserWithDisabledLastLoginField


@override_settings(ROOT_URLCONF="auth_tests.urls")
class SignalTestCase(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.u1 = User.objects.create_user(username="testclient", password="password")
        cls.u3 = User.objects.create_user(username="staff", password="password")

    def listener_login(self, user, **kwargs):
        self.logged_in.append(user)

    def listener_logout(self, user, **kwargs):
        self.logged_out.append(user)

    def listener_login_failed(self, sender, **kwargs):
        self.login_failed.append(kwargs)

    def setUp(self):
        
        self.logged_in = []
        self.logged_out = []
        self.login_failed = []
        signals.user_logged_in.connect(self.listener_login)
        signals.user_logged_out.connect(self.listener_logout)
        signals.user_login_failed.connect(self.listener_login_failed)

    def tearDown(self):
        
        signals.user_logged_in.disconnect(self.listener_login)
        signals.user_logged_out.disconnect(self.listener_logout)
        signals.user_login_failed.disconnect(self.listener_login_failed)

    def test_login(self):
        
        self.client.login(username="testclient", password="bad")
        self.assertEqual(len(self.logged_in), 0)
        self.assertEqual(len(self.login_failed), 1)
        self.assertEqual(self.login_failed[0]["credentials"]["username"], "testclient")
        
        self.assertIn("***", self.login_failed[0]["credentials"]["password"])
        self.assertIn("request", self.login_failed[0])

        
        self.client.login(username="testclient", password="password")
        self.assertEqual(len(self.logged_in), 1)
        self.assertEqual(self.logged_in[0].username, "testclient")

        
        self.assertEqual(len(self.login_failed), 1)

    def test_logout_anonymous(self):
        
        
        self.client.post("/logout/next_page/")
        self.assertEqual(len(self.logged_out), 1)
        self.assertIsNone(self.logged_out[0])

    def test_logout(self):
        self.client.login(username="testclient", password="password")
        self.client.post("/logout/next_page/")
        self.assertEqual(len(self.logged_out), 1)
        self.assertEqual(self.logged_out[0].username, "testclient")

    def test_update_last_login(self):
        
        user = self.u3
        old_last_login = user.last_login

        user.username = "This username shouldn't get saved"
        request = RequestFactory().get("/login")
        signals.user_logged_in.send(sender=user.__class__, request=request, user=user)
        user = User.objects.get(pk=user.pk)
        self.assertEqual(user.username, "staff")
        self.assertNotEqual(user.last_login, old_last_login)

    def test_failed_login_without_request(self):
        authenticate(username="testclient", password="bad")
        self.assertIsNone(self.login_failed[0]["request"])

    def test_login_with_custom_user_without_last_login_field(self):
        
        last_login_receivers = signals.user_logged_in.receivers
        try:
            signals.user_logged_in.receivers = []
            with self.assertRaises(FieldDoesNotExist):
                MinimalUser._meta.get_field("last_login")
            with self.settings(AUTH_USER_MODEL="auth_tests.MinimalUser"):
                apps.get_app_config("auth").ready()
            self.assertEqual(signals.user_logged_in.receivers, [])

            
            self.assertIsNone(UserWithDisabledLastLoginField().last_login)
            with self.settings(
                AUTH_USER_MODEL="auth_tests.UserWithDisabledLastLoginField"
            ):
                apps.get_app_config("auth").ready()
            self.assertEqual(signals.user_logged_in.receivers, [])

            with self.settings(AUTH_USER_MODEL="auth.User"):
                apps.get_app_config("auth").ready()
            self.assertEqual(len(signals.user_logged_in.receivers), 1)
        finally:
            signals.user_logged_in.receivers = last_login_receivers