Code

Ticket #10899: 10899_at_r16097.diff

File 10899_at_r16097.diff, 6.5 KB (added by prestontimmons, 3 years ago)

Updated ticket to not produce extra queries

Line 
1diff --git a/django/test/client.py b/django/test/client.py
2index 5cbc0ca..95085b5 100644
3--- a/django/test/client.py
4+++ b/django/test/client.py
5@@ -345,6 +345,7 @@ class Client(RequestFactory):
6         super(Client, self).__init__(**defaults)
7         self.handler = ClientHandler(enforce_csrf_checks)
8         self.exc_info = None
9+        self._session_store = None
10 
11     def store_exc_info(self, **kwargs):
12         """
13@@ -356,15 +357,25 @@ class Client(RequestFactory):
14         """
15         Obtains the current session variables.
16         """
17+        if self._session_store:
18+            return self._session_store
19+
20         if 'django.contrib.sessions' in settings.INSTALLED_APPS:
21             engine = import_module(settings.SESSION_ENGINE)
22-            cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
23+            cookie = self.cookies.get(settings.SESSION_COOKIE_NAME)
24             if cookie:
25-                return engine.SessionStore(cookie.value)
26-        return {}
27+                session_store = engine.SessionStore(cookie.value)
28+            else:
29+                session_store = engine.SessionStore()
30+                session_store.save()
31+                self.cookies[settings.SESSION_COOKIE_NAME] = \
32+                     session_store.session_key
33+            self._session_store = session_store
34+            return session_store
35+        else:
36+            return {}
37     session = property(_session)
38 
39-
40     def request(self, **request):
41         """
42         The master request method. Composes the environment dictionary
43@@ -374,6 +385,18 @@ class Client(RequestFactory):
44         """
45         environ = self._base_environ(**request)
46 
47+        if self._session_store:
48+            if getattr(self._session_store, "modified"):
49+                self._session_store.save()
50+
51+            if 'django.contrib.sessions' in settings.INSTALLED_APPS:
52+                # Update the session cookie since the session key can change
53+                # due to login or logout and force the session to be reloaded
54+                # on next access.
55+                self.cookies[settings.SESSION_COOKIE_NAME] = \
56+                    self._session_store.session_key
57+                self._session_store = None
58+
59         # Curry a data dictionary into an instance of the template renderer
60         # callback function.
61         data = {}
62@@ -505,14 +528,10 @@ class Client(RequestFactory):
63         user = authenticate(**credentials)
64         if user and user.is_active \
65                 and 'django.contrib.sessions' in settings.INSTALLED_APPS:
66-            engine = import_module(settings.SESSION_ENGINE)
67 
68             # Create a fake request to store login details.
69             request = HttpRequest()
70-            if self.session:
71-                request.session = self.session
72-            else:
73-                request.session = engine.SessionStore()
74+            request.session = self.session
75             login(request, user)
76 
77             # Save the session values.
78@@ -545,6 +564,7 @@ class Client(RequestFactory):
79         if session_cookie:
80             session.delete(session_key=session_cookie.value)
81         self.cookies = SimpleCookie()
82+        self._session_store = None
83 
84     def _handle_redirects(self, response, **extra):
85         "Follows any redirects by requesting responses from the server using GET."
86diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
87index fb9f6e5..1014b74 100644
88--- a/docs/topics/testing.txt
89+++ b/docs/topics/testing.txt
90@@ -1000,14 +1000,14 @@ can access these properties as part of a test condition.
91     A dictionary-like object containing session information. See the
92     :doc:`session documentation</topics/http/sessions>` for full details.
93 
94-    To modify the session and then save it, it must be stored in a variable
95-    first (because a new ``SessionStore`` is created every time this property
96-    is accessed)::
97+.. versionadded:: 1.4
98+
99+    Similar to normal Django sessions, you can manipulate sessions directly.
100+    The modified values will be saved on subsequent requests.
101 
102         def test_something(self):
103-            session = self.client.session
104-            session['somekey'] = 'test'
105-            session.save()
106+            self.client.session['somekey'] = value
107+            self.client.session['anotherkey'] = value
108 
109 .. _Cookie module documentation: http://docs.python.org/library/cookie.html
110 
111diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
112index 6757695..40848a1 100644
113--- a/tests/regressiontests/test_client_regress/models.py
114+++ b/tests/regressiontests/test_client_regress/models.py
115@@ -691,6 +691,39 @@ class SessionTests(TestCase):
116         self.assertEqual(response.status_code, 200)
117         self.assertEqual(response.content, 'YES')
118 
119+    def test_session_manipulation(self):
120+        # Check that the session can be edited as documented before #10899.
121+        session = self.client.session
122+        session["session_var"] = "foo"
123+        session.save()
124+
125+        response = self.client.get('/test_client_regress/check_session/')
126+        self.assertEqual(response.status_code, 200)
127+        self.assertEqual(response.content, 'foo')
128+
129+    def test_direct_session_manipulation(self):
130+        # Add a value to the session
131+        self.client.session['session_var'] = 'bar'
132+        self.assertEqual(self.client.session['session_var'], 'bar')
133+
134+        # Check that the session has been modified
135+        response = self.client.get('/test_client_regress/check_session/')
136+        self.assertEqual(response.status_code, 200)
137+        self.assertEqual(response.content, 'bar')
138+
139+        # Check that the session variable persists over login
140+        # when cycle_key() is called
141+        self.client.login(username='testclient', password='password')
142+        self.assertEqual(self.client.session['session_var'], 'bar')
143+
144+        response = self.client.get('/test_client_regress/check_session/')
145+        self.assertEqual(response.status_code, 200)
146+        self.assertEqual(response.content, 'bar')
147+
148+        # Check that new session is started after logout
149+        self.client.logout()
150+        self.assertEqual(self.client.session.get('session_var'), None)
151+
152     def test_logout(self):
153         """Logout should work whether the user is logged in or not (#9978)."""
154         self.client.logout()
155@@ -699,6 +732,7 @@ class SessionTests(TestCase):
156         self.client.logout()
157         self.client.logout()
158 
159+
160 class RequestMethodTests(TestCase):
161     def test_get(self):
162         "Request a view via request method GET"