Skip to content

Commit

Permalink
Fixed #18924 -- Made test.Client.logout send user_logged_out signal.
Browse files Browse the repository at this point in the history
Thanks awsum for the suggestion and Pavel Ponomarev and
Florian Hahn for the patch.
  • Loading branch information
timgraham committed Jun 4, 2013
1 parent e71b63e commit a35ed20
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 7 deletions.
18 changes: 12 additions & 6 deletions django/test/client.py
Expand Up @@ -13,7 +13,7 @@
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,
Expand Down Expand Up @@ -571,11 +571,17 @@ def logout(self):
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."
Expand Down
4 changes: 4 additions & 0 deletions docs/releases/1.6.txt
Expand Up @@ -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
==========================

Expand Down
2 changes: 1 addition & 1 deletion docs/topics/testing/overview.txt
Expand Up @@ -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
~~~~~~~~~~~~~~~~~
Expand Down
12 changes: 12 additions & 0 deletions tests/test_client_regress/models.py
@@ -0,0 +1,12 @@
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 changes: 73 additions & 0 deletions tests/test_client_regress/tests.py
Expand Up @@ -17,7 +17,10 @@
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(
Expand Down Expand Up @@ -961,6 +964,76 @@ def test_logout(self):
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"
Expand Down

0 comments on commit a35ed20

Please sign in to comment.