From 942556df2ffd3276dc127edd3cbb9d177095d882 Mon Sep 17 00:00:00 2001
From: Loic Bistuer <loic.bistuer@gmail.com>
Date: Sun, 4 May 2014 21:29:49 +0700
Subject: [PATCH] Fixed #22572 -- override_settings(ROOT_URLCONF) didn't clear
 urlresolvers._urlconfs.

Thanks Anubhav Joshi and Tim Graham for the reviews.
---
 django/test/signals.py    |  3 ++-
 tests/test_utils/tests.py | 43 +++++++++++++++++++++++++--------------
 tests/test_utils/views.py |  4 ++++
 3 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/django/test/signals.py b/django/test/signals.py
index eaa31d7494..4edf0d8752 100644
--- a/django/test/signals.py
+++ b/django/test/signals.py
@@ -129,5 +129,6 @@ def complex_setting_changed(**kwargs):
 @receiver(setting_changed)
 def root_urlconf_changed(**kwargs):
     if kwargs['setting'] == 'ROOT_URLCONF':
-        from django.core.urlresolvers import clear_url_caches
+        from django.core.urlresolvers import clear_url_caches, set_urlconf
         clear_url_caches()
+        set_urlconf(None)
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 1465c2be71..b2e4207fa5 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
 import unittest
 
 from django.conf.urls import url
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import NoReverseMatch, reverse
 from django.db import connection
 from django.forms import EmailField, IntegerField
 from django.http import HttpResponse
@@ -15,6 +15,7 @@ from django.test.utils import CaptureQueriesContext, override_settings
 from django.utils import six
 
 from .models import Person
+from .views import empty_response
 
 
 class SkippingTestCase(TestCase):
@@ -667,30 +668,42 @@ class AssertFieldOutputTests(SimpleTestCase):
         self.assertFieldOutput(MyCustomField, {}, {}, empty_value=None)
 
 
-# for OverrideSettingsTests
-def fake_view(request):
-    pass
-
-
 class FirstUrls:
-    urlpatterns = [url(r'first/$', fake_view, name='first')]
+    urlpatterns = [url(r'first/$', empty_response, name='first')]
 
 
 class SecondUrls:
-    urlpatterns = [url(r'second/$', fake_view, name='second')]
+    urlpatterns = [url(r'second/$', empty_response, name='second')]
 
 
 class OverrideSettingsTests(TestCase):
-    """
-    #21518 -- If neither override_settings nor a settings_changed receiver
-    clears the URL cache between tests, then one of these two test methods will
-    fail.
-    """
+
+    # #21518 -- If neither override_settings nor a settings_changed receiver
+    # clears the URL cache between tests, then one of test_first or
+    # test_second will fail.
 
     @override_settings(ROOT_URLCONF=FirstUrls)
-    def test_first(self):
+    def test_urlconf_first(self):
         reverse('first')
 
     @override_settings(ROOT_URLCONF=SecondUrls)
-    def test_second(self):
+    def test_urlconf_second(self):
         reverse('second')
+
+    def test_urlconf_cache(self):
+        self.assertRaises(NoReverseMatch, lambda: reverse('first'))
+        self.assertRaises(NoReverseMatch, lambda: reverse('second'))
+
+        with override_settings(ROOT_URLCONF=FirstUrls):
+            self.client.get(reverse('first'))
+            self.assertRaises(NoReverseMatch, lambda: reverse('second'))
+
+            with override_settings(ROOT_URLCONF=SecondUrls):
+                self.assertRaises(NoReverseMatch, lambda: reverse('first'))
+                self.client.get(reverse('second'))
+
+            self.client.get(reverse('first'))
+            self.assertRaises(NoReverseMatch, lambda: reverse('second'))
+
+        self.assertRaises(NoReverseMatch, lambda: reverse('first'))
+        self.assertRaises(NoReverseMatch, lambda: reverse('second'))
diff --git a/tests/test_utils/views.py b/tests/test_utils/views.py
index f561742b60..48fddba283 100644
--- a/tests/test_utils/views.py
+++ b/tests/test_utils/views.py
@@ -13,3 +13,7 @@ def get_person(request, pk):
 def no_template_used(request):
     template = loader.get_template_from_string("This is a string-based template")
     return HttpResponse(template.render(Context({})))
+
+
+def empty_response(request):
+    return HttpResponse('')