diff --git a/django/test/testcases.py b/django/test/testcases.py index fa044ba6ec..4a5188b198 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -246,6 +246,8 @@ class SimpleTestCase(unittest.TestCase): if msg_prefix: msg_prefix += ": " + e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url) + if hasattr(response, 'redirect_chain'): # The request was a followed redirect self.assertTrue(len(response.redirect_chain) > 0, @@ -259,6 +261,7 @@ class SimpleTestCase(unittest.TestCase): (response.redirect_chain[0][1], status_code)) url, status_code = response.redirect_chain[-1] + scheme, netloc, path, query, fragment = urlsplit(url) self.assertEqual(response.status_code, target_status_code, msg_prefix + "Response didn't redirect as expected: Final" @@ -276,7 +279,8 @@ class SimpleTestCase(unittest.TestCase): scheme, netloc, path, query, fragment = urlsplit(url) if fetch_redirect_response: - redirect_response = response.client.get(path, QueryDict(query)) + redirect_response = response.client.get(path, QueryDict(query), + secure=(scheme == 'https')) # Get the redirection page, using the same client that was used # to obtain the original response. @@ -285,10 +289,10 @@ class SimpleTestCase(unittest.TestCase): " response code was %d (expected %d)" % (path, redirect_response.status_code, target_status_code)) - e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url) - if not (e_scheme or e_netloc): - expected_url = urlunsplit(('http', host or 'testserver', e_path, - e_query, e_fragment)) + e_scheme = e_scheme if e_scheme else scheme or 'http' + e_netloc = e_netloc if e_netloc else host or 'testserver' + expected_url = urlunsplit((e_scheme, e_netloc, e_path, e_query, + e_fragment)) self.assertEqual(url, expected_url, msg_prefix + "Response redirected to '%s', expected '%s'" % diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index b5e124ec3e..8c5e81d0f3 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -469,6 +469,9 @@ Tests client can't fetch externals URLs, this allows you to use ``assertRedirects`` with redirects that aren't part of your Django app. +* Correct handling of scheme when making comparisons in + :meth:`~django.test.SimpleTestCase.assertRedirects`. + * The ``secure`` argument was added to all the request methods of :class:`~django.test.Client`. If ``True``, the request will be made through HTTPS. diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt index 7093138188..133931559e 100644 --- a/docs/topics/testing/overview.txt +++ b/docs/topics/testing/overview.txt @@ -1576,6 +1576,13 @@ your test suite. loaded. Since the test client can't fetch externals URLs, this is particularly useful if ``expected_url`` isn't part of your Django app. + .. versionadded:: 1.7 + + Scheme is handled correctly when making comparisons between two URLs. If + there isn't any scheme specified in the location where we are redirected to, + the original request's scheme is used. If present, the scheme in + ``expected_url`` is the one used to make the comparisons to. + .. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None) Asserts that the strings ``html1`` and ``html2`` are equal. The comparison diff --git a/tests/test_client_regress/tests.py b/tests/test_client_regress/tests.py index 04fa734ddc..5f907925ba 100644 --- a/tests/test_client_regress/tests.py +++ b/tests/test_client_regress/tests.py @@ -5,6 +5,7 @@ Regression tests for the Test Client, especially the customized assertions. from __future__ import unicode_literals import os +import itertools from django.core.urlresolvers import reverse from django.template import (TemplateSyntaxError, @@ -433,6 +434,24 @@ class AssertRedirectsTests(TestCase): except AssertionError as e: self.assertIn("abc: Response didn't redirect as expected: Response code was 200 (expected 302)", str(e)) + def test_redirect_scheme(self): + "An assertion is raised if the response doesn't have the scheme specified in expected_url" + + # Assure that original request scheme is preserved if no scheme specified in the redirect location + response = self.client.get('/test_client/redirect_view/', secure=True) + self.assertRedirects(response, 'https://testserver/test_client/get_view/') + + # For all possible True/False combinations of follow and secure + for follow, secure in itertools.product([True, False], repeat=2): + # always redirects to https + response = self.client.get('/test_client/https_redirect_view/', follow=follow, secure=secure) + # no scheme to compare too, always succeeds + self.assertRedirects(response, '/test_client/secure_view/', status_code=301) + # the goal scheme is https + self.assertRedirects(response, 'https://testserver/test_client/secure_view/', status_code=301) + with self.assertRaises(AssertionError): + self.assertRedirects(response, 'http://testserver/test_client/secure_view/', status_code=301) + class AssertFormErrorTests(TestCase): def test_unknown_form(self):