Commit a35ed202 authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #18924 -- Made test.Client.logout send user_logged_out signal.

Thanks awsum for the suggestion and Pavel Ponomarev and
Florian Hahn for the patch.
parent e71b63e2
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ except ImportError: # Python 2
    from urlparse import urlparse, urlsplit

from django.conf import settings
from django.contrib.auth import authenticate, login
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.core.signals import (request_started, request_finished,
@@ -571,11 +571,17 @@ class Client(RequestFactory):

        Causes the authenticated user to be logged out.
        """
        session = import_module(settings.SESSION_ENGINE).SessionStore()
        session_cookie = self.cookies.get(settings.SESSION_COOKIE_NAME)
        if session_cookie:
            session.delete(session_key=session_cookie.value)
        self.cookies = SimpleCookie()
        request = HttpRequest()
        engine = import_module(settings.SESSION_ENGINE)
        UserModel = get_user_model()
        if self.session:
            request.session = self.session
            uid = self.session.get("_auth_user_id")
            if uid:
                request.user = UserModel._default_manager.get(pk=uid)
        else:
            request.session = engine.SessionStore()
        logout(request)

    def _handle_redirects(self, response, **extra):
        "Follows any redirects by requesting responses from the server using GET."
+4 −0
Original line number Diff line number Diff line
@@ -623,6 +623,10 @@ Miscellaneous
  raises NoReverseMatch. There is no change to {% url %} tag, it causes
  template rendering to fail like always when NoReverseMatch is risen.

* :meth:`django.test.client.Client.logout` now calls
  :meth:`django.contrib.auth.logout` which will send the
  :func:`~django.contrib.auth.signals.user_logged_out` signal.

Features deprecated in 1.6
==========================

+1 −1
Original line number Diff line number Diff line
@@ -696,7 +696,7 @@ Use the ``django.test.client.Client`` class to make requests.

        After you call this method, the test client will have all the cookies
        and session data cleared to defaults. Subsequent requests will appear
        to come from an AnonymousUser.
        to come from an :class:`~django.contrib.auth.models.AnonymousUser`.

Testing responses
~~~~~~~~~~~~~~~~~
+12 −0
Original line number Diff line number Diff line
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager


class CustomUser(AbstractBaseUser):
    email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
    custom_objects = BaseUserManager()

    USERNAME_FIELD = 'email'

    class Meta:
        app_label = 'test_client_regress'
+73 −0
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ from django.template.response import SimpleTemplateResponse
from django.utils._os import upath
from django.utils.translation import ugettext_lazy
from django.http import HttpResponse
from django.contrib.auth.signals import user_logged_out, user_logged_in
from django.contrib.auth.models import User

from .models import CustomUser
from .views import CustomTestException

@override_settings(
@@ -961,6 +964,76 @@ class SessionTests(TestCase):
        self.client.logout()
        self.client.logout()

    def test_logout_with_user(self):
        """Logout should send user_logged_out signal if user was logged in."""
        def listener(*args, **kwargs):
            listener.executed = True
            self.assertEqual(kwargs['sender'], User)
        listener.executed = False

        user_logged_out.connect(listener)
        self.client.login(username='testclient', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)
        self.assertTrue(listener.executed)

    @override_settings(AUTH_USER_MODEL='test_client_regress.CustomUser')
    def test_logout_with_custom_user(self):
        """Logout should send user_logged_out signal if custom user was logged in."""
        def listener(*args, **kwargs):
            self.assertEqual(kwargs['sender'], CustomUser)
            listener.executed = True
        listener.executed = False
        u = CustomUser.custom_objects.create(email='test@test.com')
        u.set_password('password')
        u.save()

        user_logged_out.connect(listener)
        self.client.login(username='test@test.com', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)
        self.assertTrue(listener.executed)

    def test_logout_without_user(self):
        """Logout should send signal even if user not authenticated."""
        def listener(user, *args, **kwargs):
            listener.user = user
            listener.executed = True
        listener.executed = False

        user_logged_out.connect(listener)
        self.client.login(username='incorrect', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)

        self.assertTrue(listener.executed)
        self.assertIsNone(listener.user)

    def test_login_with_user(self):
        """Login should send user_logged_in signal on successful login."""
        def listener(*args, **kwargs):
            listener.executed = True
        listener.executed = False

        user_logged_in.connect(listener)
        self.client.login(username='testclient', password='password')
        user_logged_out.disconnect(listener)

        self.assertTrue(listener.executed)

    def test_login_without_signal(self):
        """Login shouldn't send signal if user wasn't logged in"""
        def listener(*args, **kwargs):
            listener.executed = True
        listener.executed = False

        user_logged_in.connect(listener)
        self.client.login(username='incorrect', password='password')
        user_logged_in.disconnect(listener)

        self.assertFalse(listener.executed)


class RequestMethodTests(TestCase):
    def test_get(self):
        "Request a view via request method GET"