From dff6a7345581f3bc75081e59f34e0f0b41a42f00 Mon Sep 17 00:00:00 2001 From: Matt Molyneaux Date: Fri, 4 Sep 2015 00:22:57 +0100 Subject: [PATCH 1/4] Travis config * config file for Travis CI * updates to how runtests.sh script works - it now returns the exit code of the tests rather than 0 --- .travis.yml | 23 +++++++++++++++++++++++ runtests.sh | 6 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e1e45d2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: python +sudo: false +python: + - "2.6" + - "2.7" + - "3.3" + - "3.4" + +env: + - DJANGO="Django==1.4.22" + - DJANGO="Django==1.7.10" + - DJANGO="Django==1.8.4" + +matrix: + exclude: + - python: "2.6" + env: DJANGO="Django==1.8.4" + - python: "2.6" + env: DJANGO="Django==1.7.10" + +install: pip install $DJANGO + +script: ./runtests.sh diff --git a/runtests.sh b/runtests.sh index 663ce0f..5ea052a 100755 --- a/runtests.sh +++ b/runtests.sh @@ -6,7 +6,7 @@ cat > $SETTINGS < Date: Fri, 4 Sep 2015 17:46:32 +0100 Subject: [PATCH 2/4] Update tests to work with newer versions of Django --- session_csrf/tests.py | 124 +++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/session_csrf/tests.py b/session_csrf/tests.py index 41b04d4..66b072d 100644 --- a/session_csrf/tests.py +++ b/session_csrf/tests.py @@ -2,7 +2,7 @@ import django.test from django import http -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns from django.contrib.auth import logout from django.contrib.auth.middleware import AuthenticationMiddleware from django.contrib.auth.models import User @@ -11,8 +11,7 @@ from django.core import signals from django.core.cache import cache from django.core.handlers.wsgi import WSGIRequest -from django.db import close_connection -from django.template import context +from django.core.exceptions import ImproperlyConfigured import mock @@ -46,33 +45,33 @@ def login(self): def test_csrftoken_unauthenticated(self): # request.csrf_token is '' for anonymous users. response = self.client.get('/', follow=True) - self.assertEqual(response._request.csrf_token, '') + self.assertEqual(response.wsgi_request.csrf_token, '') def test_csrftoken_authenticated(self): # request.csrf_token is a random non-empty string for authed users. self.login() response = self.client.get('/', follow=True) # The CSRF token is a 32-character MD5 string. - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) def test_csrftoken_new_session(self): # The csrf_token is added to request.session the first time. self.login() response = self.client.get('/', follow=True) # The CSRF token is a 32-character MD5 string. - token = response._request.session['csrf_token'] + token = response.wsgi_request.session['csrf_token'] self.assertEqual(len(token), 32) - self.assertEqual(token, response._request.csrf_token) + self.assertEqual(token, response.wsgi_request.csrf_token) def test_csrftoken_existing_session(self): # The csrf_token in request.session is reused on subsequent requests. self.login() r1 = self.client.get('/', follow=True) - token = r1._request.session['csrf_token'] + token = r1.wsgi_request.session['csrf_token'] r2 = self.client.get('/', follow=True) - self.assertEqual(r1._request.csrf_token, r2._request.csrf_token) - self.assertEqual(token, r2._request.csrf_token) + self.assertEqual(r1.wsgi_request.csrf_token, r2.wsgi_request.csrf_token) + self.assertEqual(token, r2.wsgi_request.csrf_token) class TestCsrfMiddleware(django.test.TestCase): @@ -160,7 +159,7 @@ def test_csrf_token_context_processor(self): request.csrf_token = self.token request.groups = [] ctx = {} - for processor in context.get_standard_processors(): + for processor in get_context_processors(): ctx.update(processor(request)) self.assertEqual(ctx['csrf_token'], self.token) @@ -209,7 +208,7 @@ def test_new_anon_token_on_request(self): response = self.client.get('/anon') # Get the key from the cookie and find the token in the cache. key = response.cookies['anoncsrf'].value - self.assertEqual(response._request.csrf_token, cache.get(prep_key(key))) + self.assertEqual(response.wsgi_request.csrf_token, cache.get(prep_key(key))) def test_existing_anon_cookie_on_request(self): # We reuse an existing anon cookie key+token. @@ -218,7 +217,7 @@ def test_existing_anon_cookie_on_request(self): # Now check that subsequent requests use that cookie. response = self.client.get('/anon') self.assertEqual(response.cookies['anoncsrf'].value, key) - self.assertEqual(response._request.csrf_token, cache.get(prep_key(key))) + self.assertEqual(response.wsgi_request.csrf_token, cache.get(prep_key(key))) def test_new_anon_token_on_response(self): # The anon cookie is sent and we vary on Cookie. @@ -244,12 +243,12 @@ def test_anon_csrf_logout(self): def test_existing_anon_cookie_not_in_cache(self): response = self.client.get('/anon') - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) # Clear cache and make sure we still get a token cache.clear() response = self.client.get('/anon') - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) def test_anonymous_csrf_exempt(self): response = self.client.post('/no-anon-csrf') @@ -283,7 +282,7 @@ def test_csrftoken_unauthenticated(self): # when ANON_ALWAYS is enabled. response = self.client.get('/', follow=True) # The CSRF token is a 32-character MD5 string. - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) def test_authenticated_request(self): # Nothing special happens, nothing breaks. @@ -307,7 +306,7 @@ def test_new_anon_token_on_request(self): response = self.client.get('/') # Get the key from the cookie and find the token in the cache. key = response.cookies['anoncsrf'].value - self.assertEqual(response._request.csrf_token, cache.get(prep_key(key))) + self.assertEqual(response.wsgi_request.csrf_token, cache.get(prep_key(key))) def test_existing_anon_cookie_on_request(self): # We reuse an existing anon cookie key+token. @@ -317,7 +316,7 @@ def test_existing_anon_cookie_on_request(self): # Now check that subsequent requests use that cookie. response = self.client.get('/') self.assertEqual(response.cookies['anoncsrf'].value, key) - self.assertEqual(response._request.csrf_token, cache.get(prep_key(key))) + self.assertEqual(response.wsgi_request.csrf_token, cache.get(prep_key(key))) self.assertEqual(response['Vary'], 'Cookie') def test_anon_csrf_logout(self): @@ -328,12 +327,12 @@ def test_anon_csrf_logout(self): def test_existing_anon_cookie_not_in_cache(self): response = self.client.get('/') - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) # Clear cache and make sure we still get a token cache.clear() response = self.client.get('/') - self.assertEqual(len(response._request.csrf_token), 32) + self.assertEqual(len(response.wsgi_request.csrf_token), 32) def test_massive_anon_cookie(self): # if the key + PREFIX + setting prefix is greater than 250 @@ -352,33 +351,60 @@ def test_surprising_characters(self): self.assertEqual(warner.call_count, 0) -class ClientHandler(django.test.client.ClientHandler): - """ - Handler that stores the real request object on the response. - - Almost all the code comes from the parent class. - """ - - def __call__(self, environ): - # Set up middleware if needed. We couldn't do this earlier, because - # settings weren't available. - if self._request_middleware is None: - self.load_middleware() - - signals.request_started.send(sender=self.__class__) +def get_context_processors(): + """Get context processors in a way that works for Django 1.4, 1.7, and 1.8""" + try: + from django.template.context import get_standard_processors + return get_standard_processors() + except ImportError: try: - request = WSGIRequest(environ) - # sneaky little hack so that we can easily get round - # CsrfViewMiddleware. This makes life easier, and is probably - # required for backwards compatibility with external tests against - # admin views. - request._dont_enforce_csrf_checks = not self.enforce_csrf_checks - response = self.get_response(request) - finally: - signals.request_finished.disconnect(close_connection) - signals.request_finished.send(sender=self.__class__) - signals.request_finished.connect(close_connection) - - # Store the request object. - response._request = request - return response + from django.template.engine import Engine + engine = Engine.get_default() + except ImproperlyConfigured: + return [] + return engine.template_context_processors + +try: + # for Django 1.4 support + from django.db import close_connection + + class ClientHandler(django.test.client.ClientHandler): + """ + Handler that stores the real request object on the response. + + Almost all the code comes from the parent class. + """ + + def __call__(self, environ): + # Set up middleware if needed. We couldn't do this earlier, because + # settings weren't available. + if self.wsgi_request_middleware is None: + self.load_middleware() + + signals.request_started.send(sender=self.__class__) + try: + request = WSGIRequest(environ) + # sneaky little hack so that we can easily get round + # CsrfViewMiddleware. This makes life easier, and is probably + # required for backwards compatibility with external tests against + # admin views. + request._dont_enforce_csrf_checks = not self.enforce_csrf_checks + response = self.get_response(request) + finally: + signals.request_finished.disconnect(close_connection) + signals.request_finished.send(sender=self.__class__) + signals.request_finished.connect(close_connection) + + # Store the request object. + response.wsgi_request = request + return response + + @property + def wsgi_request_middleware(self): + return self._request_middleware +except ImportError: + # for 1.7 support + class ClientHandler(django.test.client.ClientHandler): + @property + def wsgi_request_middleware(self): + return self._request_middleware From c0b115528512c8189f9baecf886b44091edff75a Mon Sep 17 00:00:00 2001 From: Matt Molyneaux Date: Fri, 4 Sep 2015 18:12:49 +0100 Subject: [PATCH 3/4] Don't test on Python 3, it's broken --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1e45d2..774e076 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,6 @@ sudo: false python: - "2.6" - "2.7" - - "3.3" - - "3.4" env: - DJANGO="Django==1.4.22" From ab97e335993fe8ca0cc81559f41bb7a5992eaf97 Mon Sep 17 00:00:00 2001 From: Matt Molyneaux Date: Thu, 10 Mar 2016 00:59:44 +0000 Subject: [PATCH 4/4] Change tested versions * Drop support for 1.4 * Test with 1.9 * Stop testing against Python 2.6 --- .travis.yml | 14 +++-------- session_csrf/tests.py | 54 ++++++++----------------------------------- 2 files changed, 12 insertions(+), 56 deletions(-) diff --git a/.travis.yml b/.travis.yml index 774e076..5ab03d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,12 @@ language: python sudo: false python: - - "2.6" - "2.7" env: - - DJANGO="Django==1.4.22" - - DJANGO="Django==1.7.10" - - DJANGO="Django==1.8.4" - -matrix: - exclude: - - python: "2.6" - env: DJANGO="Django==1.8.4" - - python: "2.6" - env: DJANGO="Django==1.7.10" + - DJANGO="Django==1.7.11" + - DJANGO="Django==1.8.11" + - DJANGO="Django==1.9.4" install: pip install $DJANGO diff --git a/session_csrf/tests.py b/session_csrf/tests.py index 66b072d..f4035b2 100644 --- a/session_csrf/tests.py +++ b/session_csrf/tests.py @@ -352,11 +352,13 @@ def test_surprising_characters(self): def get_context_processors(): - """Get context processors in a way that works for Django 1.4, 1.7, and 1.8""" + """Get context processors in a way that works for Django 1.7 and 1.8+""" try: + # 1.7 from django.template.context import get_standard_processors return get_standard_processors() except ImportError: + # 1.8+ try: from django.template.engine import Engine engine = Engine.get_default() @@ -364,47 +366,9 @@ def get_context_processors(): return [] return engine.template_context_processors -try: - # for Django 1.4 support - from django.db import close_connection - - class ClientHandler(django.test.client.ClientHandler): - """ - Handler that stores the real request object on the response. - - Almost all the code comes from the parent class. - """ - - def __call__(self, environ): - # Set up middleware if needed. We couldn't do this earlier, because - # settings weren't available. - if self.wsgi_request_middleware is None: - self.load_middleware() - - signals.request_started.send(sender=self.__class__) - try: - request = WSGIRequest(environ) - # sneaky little hack so that we can easily get round - # CsrfViewMiddleware. This makes life easier, and is probably - # required for backwards compatibility with external tests against - # admin views. - request._dont_enforce_csrf_checks = not self.enforce_csrf_checks - response = self.get_response(request) - finally: - signals.request_finished.disconnect(close_connection) - signals.request_finished.send(sender=self.__class__) - signals.request_finished.connect(close_connection) - - # Store the request object. - response.wsgi_request = request - return response - - @property - def wsgi_request_middleware(self): - return self._request_middleware -except ImportError: - # for 1.7 support - class ClientHandler(django.test.client.ClientHandler): - @property - def wsgi_request_middleware(self): - return self._request_middleware + +# for 1.7 support +class ClientHandler(django.test.client.ClientHandler): + @property + def wsgi_request_middleware(self): + return self._request_middleware