diff --git a/cms/djangoapps/course_creators/tests/test_views.py b/cms/djangoapps/course_creators/tests/test_views.py index c88d0df72a..545b86501d 100644 --- a/cms/djangoapps/course_creators/tests/test_views.py +++ b/cms/djangoapps/course_creators/tests/test_views.py @@ -2,15 +2,16 @@ Tests course_creators.views.py. """ -from django.test import TestCase from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from django.test import TestCase, RequestFactory from course_creators.views import add_user_with_status_unrequested, add_user_with_status_granted from course_creators.views import get_course_creator_status, update_course_creator_group, user_requested_access import mock from student.roles import CourseCreatorRole from student import auth +from edxmako.tests import mako_middleware_process_request class CourseCreatorView(TestCase): @@ -70,6 +71,11 @@ class CourseCreatorView(TestCase): def test_user_requested_access(self): add_user_with_status_unrequested(self.user) self.assertEqual('unrequested', get_course_creator_status(self.user)) + + request = RequestFactory().get('/') + request.user = self.user + + mako_middleware_process_request(request) user_requested_access(self.user) self.assertEqual('pending', get_course_creator_status(self.user)) diff --git a/common/djangoapps/edxmako/middleware.py b/common/djangoapps/edxmako/middleware.py index 27b129f571..17f164272a 100644 --- a/common/djangoapps/edxmako/middleware.py +++ b/common/djangoapps/edxmako/middleware.py @@ -12,15 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +import threading from django.template import RequestContext from util.request import safe_get_host -requestcontext = None + +REQUEST_CONTEXT = threading.local() class MakoMiddleware(object): def process_request(self, request): - global requestcontext - requestcontext = RequestContext(request) - requestcontext['is_secure'] = request.is_secure() - requestcontext['site'] = safe_get_host(request) + REQUEST_CONTEXT.context = RequestContext(request) + REQUEST_CONTEXT.context['is_secure'] = request.is_secure() + REQUEST_CONTEXT.context['site'] = safe_get_host(request) + + def process_response(self, request, response): + REQUEST_CONTEXT.context = None + return response diff --git a/common/djangoapps/edxmako/shortcuts.py b/common/djangoapps/edxmako/shortcuts.py index b8d0c2a2c2..01b7cc0e55 100644 --- a/common/djangoapps/edxmako/shortcuts.py +++ b/common/djangoapps/edxmako/shortcuts.py @@ -92,8 +92,8 @@ def render_to_string(template_name, dictionary, context=None, namespace='main'): context_instance['marketing_link'] = marketing_link # In various testing contexts, there might not be a current request context. - if edxmako.middleware.requestcontext is not None: - for d in edxmako.middleware.requestcontext: + if edxmako.middleware.REQUEST_CONTEXT.context is not None: + for d in edxmako.middleware.REQUEST_CONTEXT.context: context_dictionary.update(d) for d in context_instance: context_dictionary.update(d) diff --git a/common/djangoapps/edxmako/template.py b/common/djangoapps/edxmako/template.py index 209b4d6c4f..712d5184e1 100644 --- a/common/djangoapps/edxmako/template.py +++ b/common/djangoapps/edxmako/template.py @@ -48,8 +48,8 @@ class Template(MakoTemplate): context_dictionary = {} # In various testing contexts, there might not be a current request context. - if edxmako.middleware.requestcontext is not None: - for d in edxmako.middleware.requestcontext: + if edxmako.middleware.REQUEST_CONTEXT.context is not None: + for d in edxmako.middleware.REQUEST_CONTEXT.context: context_dictionary.update(d) for d in context_instance: context_dictionary.update(d) diff --git a/common/djangoapps/edxmako/tests.py b/common/djangoapps/edxmako/tests.py index 2fc79bb348..b9aafa2d66 100644 --- a/common/djangoapps/edxmako/tests.py +++ b/common/djangoapps/edxmako/tests.py @@ -1,9 +1,14 @@ + +from mock import patch, Mock +from django.http import HttpResponse from django.test import TestCase from django.test.utils import override_settings +from django.test.client import RequestFactory from django.core.urlresolvers import reverse +import edxmako.middleware from edxmako import add_lookup, LOOKUP from edxmako.shortcuts import marketing_link -from mock import patch +from student.tests.factories import UserFactory from util.testing import UrlResetMixin @@ -37,3 +42,40 @@ class AddLookupTests(TestCase): dirs = LOOKUP['test'].directories self.assertEqual(len(dirs), 1) self.assertTrue(dirs[0].endswith('management')) + + +class MakoMiddlewareTest(TestCase): + """ + Test MakoMiddleware. + """ + + def setUp(self): + self.middleware = edxmako.middleware.MakoMiddleware() + self.user = UserFactory.create() + self.url = "/" + self.request = RequestFactory().get(self.url) + self.request.user = self.user + self.response = Mock(spec=HttpResponse) + + def test_clear_request_context_variable(self): + """ + Test the global variable requestcontext is cleared correctly + when response middleware is called. + """ + + self.middleware.process_request(self.request) + # requestcontext should not be None. + self.assertIsNotNone(edxmako.middleware.REQUEST_CONTEXT.context) + + self.middleware.process_response(self.request, self.response) + # requestcontext should be None. + self.assertIsNone(edxmako.middleware.REQUEST_CONTEXT.context) + + +def mako_middleware_process_request(request): + """ + Initialize the global RequestContext variable + edxmako.middleware.requestcontext using the request object. + """ + mako_middleware = edxmako.middleware.MakoMiddleware() + mako_middleware.process_request(request) diff --git a/common/djangoapps/external_auth/tests/test_shib.py b/common/djangoapps/external_auth/tests/test_shib.py index 3226631476..acf095ee8d 100644 --- a/common/djangoapps/external_auth/tests/test_shib.py +++ b/common/djangoapps/external_auth/tests/test_shib.py @@ -27,6 +27,7 @@ from external_auth.views import shib_login, course_specific_login, course_specif from student.views import create_account, change_enrollment from student.models import UserProfile, Registration, CourseEnrollment from student.tests.factories import UserFactory +from edxmako.tests import mako_middleware_process_request TEST_DATA_MIXED_MODULESTORE = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}) @@ -91,6 +92,9 @@ class ShibSPTest(ModuleStoreTestCase): """ no_remote_user_request = self.request_factory.get('/shib-login') no_remote_user_request.META.update({'Shib-Identity-Provider': IDP}) + no_remote_user_request.user = AnonymousUser() + + mako_middleware_process_request(no_remote_user_request) no_remote_user_response = shib_login(no_remote_user_request) self.assertEqual(no_remote_user_response.status_code, 403) self.assertIn("identity server did not return your ID information", no_remote_user_response.content) @@ -155,6 +159,8 @@ class ShibSPTest(ModuleStoreTestCase): 'REMOTE_USER': remote_user, 'mail': remote_user}) request.user = AnonymousUser() + + mako_middleware_process_request(request) with patch('external_auth.views.AUDIT_LOG') as mock_audit_log: response = shib_login(request) audit_log_calls = mock_audit_log.method_calls @@ -315,6 +321,8 @@ class ShibSPTest(ModuleStoreTestCase): request2 = self.request_factory.post('/create_account', data=postvars) request2.session = client.session request2.user = AnonymousUser() + + mako_middleware_process_request(request2) with patch('student.views.AUDIT_LOG') as mock_audit_log: _response2 = create_account(request2) diff --git a/common/djangoapps/student/tests/test_email.py b/common/djangoapps/student/tests/test_email.py index 3148443bc2..1a09a3023f 100644 --- a/common/djangoapps/student/tests/test_email.py +++ b/common/djangoapps/student/tests/test_email.py @@ -1,3 +1,4 @@ + import json import django.db import unittest @@ -12,6 +13,7 @@ from mock import Mock, patch from django.http import Http404, HttpResponse from django.conf import settings from edxmako.shortcuts import render_to_string +from edxmako.tests import mako_middleware_process_request from util.request import safe_get_host from textwrap import dedent @@ -93,9 +95,11 @@ class ReactivationEmailTests(EmailTestMixin, TestCase): # Thorough tests for safe_get_host are elsewhere; here we just want a quick URL sanity check request = RequestFactory().post('unused_url') + request.user = self.user request.META['HTTP_HOST'] = "aGenericValidHostName" self.append_allowed_hosts("aGenericValidHostName") + mako_middleware_process_request(request) body = render_to_string('emails/activation_email.txt', context) host = safe_get_host(request) @@ -248,9 +252,11 @@ class EmailChangeConfirmationTests(EmailTestMixin, TransactionTestCase): # Thorough tests for safe_get_host are elsewhere; here we just want a quick URL sanity check request = RequestFactory().post('unused_url') + request.user = self.user request.META['HTTP_HOST'] = "aGenericValidHostName" self.append_allowed_hosts("aGenericValidHostName") + mako_middleware_process_request(request) body = render_to_string('emails/confirm_email_change.txt', context) url = safe_get_host(request) diff --git a/common/djangoapps/student/tests/test_password_policy.py b/common/djangoapps/student/tests/test_password_policy.py index 28cd43e369..68f776e775 100644 --- a/common/djangoapps/student/tests/test_password_policy.py +++ b/common/djangoapps/student/tests/test_password_policy.py @@ -6,12 +6,14 @@ import json from django.test import TestCase from django.test.client import RequestFactory from django.core.urlresolvers import reverse +from django.contrib.auth.models import AnonymousUser from django.utils.importlib import import_module from django.test.utils import override_settings from django.conf import settings from mock import patch -from student.views import create_account +from edxmako.tests import mako_middleware_process_request from external_auth.models import ExternalAuthMap +from student.views import create_account @patch.dict("django.conf.settings.FEATURES", {'ENFORCE_PASSWORD_POLICY': True}) class TestPasswordPolicy(TestCase): @@ -255,6 +257,9 @@ class TestPasswordPolicy(TestCase): internal_password=self.url_params['password'], external_domain='shib:https://idp.stanford.edu/') request.session['ExternalAuthMap'] = extauth + request.user = AnonymousUser() + + mako_middleware_process_request(request) response = create_account(request) self.assertEqual(response.status_code, 200) obj = json.loads(response.content) diff --git a/common/djangoapps/third_party_auth/tests/specs/base.py b/common/djangoapps/third_party_auth/tests/specs/base.py index c00290a28e..3135032975 100644 --- a/common/djangoapps/third_party_auth/tests/specs/base.py +++ b/common/djangoapps/third_party_auth/tests/specs/base.py @@ -13,6 +13,7 @@ from django.contrib.messages.storage import fallback from django.contrib.sessions.backends import cache from django.test import utils as django_utils from django.conf import settings as django_settings +from edxmako.tests import mako_middleware_process_request from social import actions, exceptions from social.apps.django_app import utils as social_utils from social.apps.django_app import views as social_views @@ -420,6 +421,8 @@ class IntegrationTest(testutil.TestCase, test.TestCase): self.client.get( pipeline.get_login_url(self.PROVIDER_CLASS.NAME, pipeline.AUTH_ENTRY_LOGIN)) actions.do_complete(strategy, social_views._do_login) # pylint: disable-msg=protected-access + + mako_middleware_process_request(strategy.request) student_views.signin_user(strategy.request) student_views.login_user(strategy.request) actions.do_complete(strategy, social_views._do_login) # pylint: disable-msg=protected-access @@ -453,6 +456,8 @@ class IntegrationTest(testutil.TestCase, test.TestCase): self.client.get( pipeline.get_login_url(self.PROVIDER_CLASS.NAME, pipeline.AUTH_ENTRY_LOGIN)) actions.do_complete(strategy, social_views._do_login) # pylint: disable-msg=protected-access + + mako_middleware_process_request(strategy.request) student_views.signin_user(strategy.request) student_views.login_user(strategy.request) actions.do_complete(strategy, social_views._do_login, user=user) # pylint: disable-msg=protected-access @@ -508,6 +513,8 @@ class IntegrationTest(testutil.TestCase, test.TestCase): self.client.get('/login') self.client.get(pipeline.get_login_url(self.PROVIDER_CLASS.NAME, pipeline.AUTH_ENTRY_LOGIN)) actions.do_complete(strategy, social_views._do_login) # pylint: disable-msg=protected-access + + mako_middleware_process_request(strategy.request) student_views.signin_user(strategy.request) student_views.login_user(strategy.request) actions.do_complete(strategy, social_views._do_login, user=user) # pylint: disable-msg=protected-access @@ -547,6 +554,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase): # pylint: disable-msg=protected-access self.assert_redirect_to_login_looks_correct(actions.do_complete(strategy, social_views._do_login)) + mako_middleware_process_request(strategy.request) # At this point we know the pipeline has resumed correctly. Next we # fire off the view that displays the login form and posts it via JS. self.assert_login_response_in_pipeline_looks_correct(student_views.signin_user(strategy.request)) @@ -568,6 +576,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase): user.is_active = False user.save() + mako_middleware_process_request(strategy.request) self.assert_json_failure_response_is_inactive_account(student_views.login_user(strategy.request)) def test_signin_fails_if_no_account_associated(self): @@ -613,6 +622,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase): # pylint:disable-msg=protected-access self.assert_redirect_to_register_looks_correct(actions.do_complete(strategy, social_views._do_login)) + mako_middleware_process_request(strategy.request) # At this point we know the pipeline has resumed correctly. Next we # fire off the view that displays the registration form. self.assert_register_response_in_pipeline_looks_correct( @@ -672,6 +682,8 @@ class IntegrationTest(testutil.TestCase, test.TestCase): strategy.backend.auth_complete = mock.MagicMock(return_value=self.fake_auth_complete(strategy)) # pylint:disable-msg=protected-access self.assert_redirect_to_register_looks_correct(actions.do_complete(strategy, social_views._do_login)) + + mako_middleware_process_request(strategy.request) self.assert_register_response_in_pipeline_looks_correct( student_views.register_user(strategy.request), pipeline.get(request)['kwargs']) strategy.request.POST = self.get_registration_post_vars() diff --git a/lms/djangoapps/branding/tests.py b/lms/djangoapps/branding/tests.py index 5faab59a7a..0c369e52ee 100644 --- a/lms/djangoapps/branding/tests.py +++ b/lms/djangoapps/branding/tests.py @@ -15,6 +15,7 @@ from xmodule.modulestore.tests.factories import CourseFactory from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE import student.views from branding.views import index +from edxmako.tests import mako_middleware_process_request FEATURES_WITH_STARTDATE = settings.FEATURES.copy() FEATURES_WITH_STARTDATE['DISABLE_START_DATES'] = False @@ -45,6 +46,8 @@ class AnonymousIndexPageTest(ModuleStoreTestCase): """ request = self.factory.get('/') request.user = AnonymousUser() + + mako_middleware_process_request(request) student.views.index(request) @override_settings(FEATURES=FEATURES_WITH_STARTDATE) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 7cba9efdcb..4906d4c8d8 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -20,6 +20,7 @@ from django.core.urlresolvers import reverse from student.models import CourseEnrollment from student.tests.factories import AdminFactory from edxmako.middleware import MakoMiddleware +from edxmako.tests import mako_middleware_process_request from opaque_keys.edx.locations import Location from xmodule.modulestore.django import modulestore @@ -413,6 +414,8 @@ class TestProgressDueDate(BaseDueDateTests): def get_text(self, course): """ Returns the HTML for the progress page """ + + mako_middleware_process_request(self.request) return views.progress(self.request, course.id.to_deprecated_string(), self.user.id).content diff --git a/lms/djangoapps/django_comment_client/forum/tests.py b/lms/djangoapps/django_comment_client/forum/tests.py index 4ad9c72aa3..e402adad98 100644 --- a/lms/djangoapps/django_comment_client/forum/tests.py +++ b/lms/djangoapps/django_comment_client/forum/tests.py @@ -4,6 +4,7 @@ from django.test.utils import override_settings from django.test.client import Client, RequestFactory from xmodule.modulestore.tests.factories import CourseFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory +from edxmako.tests import mako_middleware_process_request from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from django.core.urlresolvers import reverse from util.testing import UrlResetMixin @@ -276,6 +277,8 @@ class UserProfileTestCase(ModuleStoreTestCase): mock_request.side_effect = make_mock_request_impl(self.TEST_THREAD_TEXT, self.TEST_THREAD_ID) request = RequestFactory().get("dummy_url", data=params, **headers) request.user = self.student + + mako_middleware_process_request(request) response = views.user_profile( request, self.course.id.to_deprecated_string(), diff --git a/lms/djangoapps/instructor/tests/test_legacy_xss.py b/lms/djangoapps/instructor/tests/test_legacy_xss.py index 9c807b022c..0c6ac436f8 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_xss.py +++ b/lms/djangoapps/instructor/tests/test_legacy_xss.py @@ -9,6 +9,7 @@ from markupsafe import escape from courseware.tests.tests import TEST_DATA_MIXED_MODULESTORE from student.tests.factories import UserFactory, CourseEnrollmentFactory +from edxmako.tests import mako_middleware_process_request from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -48,6 +49,8 @@ class TestXss(ModuleStoreTestCase): ) req.user = self._instructor req.session = {} + + mako_middleware_process_request(req) resp = legacy.instructor_dashboard(req, self._course.id.to_deprecated_string()) respUnicode = resp.content.decode(settings.DEFAULT_CHARSET) self.assertNotIn(self._evil_student.profile.name, respUnicode) diff --git a/lms/djangoapps/notification_prefs/tests.py b/lms/djangoapps/notification_prefs/tests.py index f464527df3..d2d245c35a 100644 --- a/lms/djangoapps/notification_prefs/tests.py +++ b/lms/djangoapps/notification_prefs/tests.py @@ -11,6 +11,7 @@ from mock import Mock, patch from notification_prefs import NOTIFICATION_PREF_KEY from notification_prefs.views import ajax_enable, ajax_disable, ajax_status, set_subscription, UsernameCipher from student.tests.factories import UserFactory +from edxmako.tests import mako_middleware_process_request from user_api.models import UserPreference from util.testing import UrlResetMixin @@ -220,6 +221,8 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): def test_user(user): request = self.request_factory.get("dummy") request.user = AnonymousUser() + + mako_middleware_process_request(request) response = set_subscription(request, self.tokens[user], subscribe=False) self.assertEqual(response.status_code, 200) self.assertNotPrefExists(user) @@ -231,6 +234,8 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): self.create_prefs() request = self.request_factory.get("dummy") request.user = AnonymousUser() + + mako_middleware_process_request(request) set_subscription(request, self.tokens[self.user], False) response = set_subscription(request, self.tokens[self.user], subscribe=False) self.assertEqual(response.status_code, 200) @@ -242,6 +247,8 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): self.assertFalse(UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY)) request = self.request_factory.get("dummy") request.user = AnonymousUser() + + mako_middleware_process_request(request) response = set_subscription(request, self.tokens[user], subscribe=True) self.assertEqual(response.status_code, 200) self.assertPrefValid(user) diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index 9403ca93e1..811c85d46c 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -3,6 +3,7 @@ Tests for open ended grading interfaces ./manage.py lms --settings test test lms/djangoapps/open_ended_grading """ +from django.test import RequestFactory import json import logging @@ -29,6 +30,7 @@ from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from lms.lib.xblock.runtime import LmsModuleSystem from student.roles import CourseStaffRole from edxmako.shortcuts import render_to_string +from edxmako.tests import mako_middleware_process_request from student.models import unique_id_for_user from open_ended_grading import staff_grading_service, views, utils @@ -471,7 +473,12 @@ class TestPanel(ModuleStoreTestCase): Ensure that the problem list from the grading controller server can be rendered properly locally @return: """ - request = Mock(user=self.user) + request = RequestFactory().get( + reverse("open_ended_problems", kwargs={'course_id': self.course_key}) + ) + request.user = self.user + + mako_middleware_process_request(request) response = views.student_problem_list(request, self.course.id.to_deprecated_string()) self.assertRegexpMatches(response.content, "Here is a list of open ended problems for this course.")