Files
edx-platform/lms/djangoapps/courseware/tests/test_masquerade.py
Calen Pennington b353ed2ea2 Better support specifying of modulestore configuration in test cases
The existing pattern of using `override_settings(MODULESTORE=...)` prevented
us from having more than one layer of subclassing in modulestore tests.

In a structure like:

    @override_settings(MODULESTORE=store_a)
    class BaseTestCase(ModuleStoreTestCase):
        def setUp(self):
            # use store

    @override_settings(MODULESTORE=store_b)
    class ChildTestCase(BaseTestCase):
        def setUp(self):
            # use store

In this case, the store actions performed in `BaseTestCase` on behalf of
`ChildTestCase` would still use `store_a`, even though the `ChildTestCase`
had specified to use `store_b`. This is because the `override_settings`
decorator would be the innermost wrapper around the `BaseTestCase.setUp` method,
no matter what `ChildTestCase` does.

To remedy this, we move the call to `override_settings` into the
`ModuleStoreTestCase.setUp` method, and use a cleanup to remove the override.
Subclasses can just defined the `MODULESTORE` class attribute to specify which
modulestore to use _for the entire `setUp` chain_.

[PLAT-419]
2015-02-04 09:09:14 -05:00

252 lines
9.2 KiB
Python

"""
Unit tests for masquerade.
"""
import json
from mock import patch
from datetime import datetime
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.utils.timezone import UTC
from capa.tests.response_xml_factory import OptionResponseXMLFactory
from courseware.masquerade import handle_ajax, setup_masquerade, get_masquerading_group_info
from courseware.tests.factories import StaffFactory
from courseware.tests.helpers import LoginEnrollmentTestCase, get_request_for_user
from student.tests.factories import UserFactory
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, TEST_DATA_MOCK_MODULESTORE
from xmodule.modulestore.tests.factories import ItemFactory, CourseFactory
from xmodule.partitions.partitions import Group, UserPartition
class MasqueradeTestCase(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
Base class for masquerade tests that sets up a test course and enrolls a user in the course.
"""
def setUp(self):
super(MasqueradeTestCase, self).setUp()
# By default, tests run with DISABLE_START_DATES=True. To test that masquerading as a student is
# working properly, we must use start dates and set a start date in the past (otherwise the access
# checks exist prematurely).
self.course = CourseFactory.create(number='masquerade-test', metadata={'start': datetime.now(UTC())})
self.chapter = ItemFactory.create(
parent_location=self.course.location,
category="chapter",
display_name="Test Section",
)
self.sequential_display_name = "Test Masquerade Subsection"
self.sequential = ItemFactory.create(
parent_location=self.chapter.location,
category="sequential",
display_name=self.sequential_display_name,
)
self.vertical = ItemFactory.create(
parent_location=self.sequential.location,
category="vertical",
display_name="Test Unit",
)
problem_xml = OptionResponseXMLFactory().build_xml(
question_text='The correct answer is Correct',
num_inputs=2,
weight=2,
options=['Correct', 'Incorrect'],
correct_option='Correct'
)
self.problem_display_name = "Test Masquerade Problem"
self.problem = ItemFactory.create(
parent_location=self.vertical.location,
category='problem',
data=problem_xml,
display_name=self.problem_display_name
)
self.test_user = self.create_user()
self.login(self.test_user.email, 'test')
self.enroll(self.course, True)
def get_courseware_page(self):
"""
Returns the server response for the courseware page.
"""
url = reverse(
'courseware_section',
kwargs={
'course_id': unicode(self.course.id),
'chapter': self.chapter.location.name,
'section': self.sequential.location.name,
}
)
return self.client.get(url)
def _create_mock_json_request(self, user, body, method='POST', session=None):
"""
Returns a mock JSON request for the specified user
"""
request = get_request_for_user(user)
request.method = method
request.META = {'CONTENT_TYPE': ['application/json']}
request.body = body
request.session = session or {}
return request
def verify_staff_debug_present(self, staff_debug_expected):
"""
Verifies that the staff debug control visibility is as expected (for staff only).
"""
content = self.get_courseware_page().content
self.assertTrue(self.sequential_display_name in content, "Subsection should be visible")
self.assertEqual(staff_debug_expected, 'Staff Debug Info' in content)
def get_problem(self):
"""
Returns the JSON content for the problem in the course.
"""
problem_url = reverse(
'xblock_handler',
kwargs={
'course_id': unicode(self.course.id),
'usage_id': unicode(self.problem.location),
'handler': 'xmodule_handler',
'suffix': 'problem_get'
}
)
return self.client.get(problem_url)
def verify_show_answer_present(self, show_answer_expected):
"""
Verifies that "Show Answer" is only present when expected (for staff only).
"""
problem_html = json.loads(self.get_problem().content)['html']
self.assertTrue(self.problem_display_name in problem_html)
self.assertEqual(show_answer_expected, "Show Answer" in problem_html)
class NormalStudentVisibilityTest(MasqueradeTestCase):
"""
Verify the course displays as expected for a "normal" student (to ensure test setup is correct).
"""
def create_user(self):
"""
Creates a normal student user.
"""
return UserFactory()
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_staff_debug_not_visible(self):
"""
Tests that staff debug control is not present for a student.
"""
self.verify_staff_debug_present(False)
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_show_answer_not_visible(self):
"""
Tests that "Show Answer" is not visible for a student.
"""
self.verify_show_answer_present(False)
class StaffMasqueradeTestCase(MasqueradeTestCase):
"""
Base class for tests of the masquerade behavior for a staff member.
"""
def create_user(self):
"""
Creates a staff user.
"""
return StaffFactory(course_key=self.course.id)
def update_masquerade(self, role, group_id=None):
"""
Toggle masquerade state.
"""
masquerade_url = reverse(
'masquerade_update',
kwargs={
'course_key_string': unicode(self.course.id),
}
)
response = self.client.post(
masquerade_url,
json.dumps({"role": role, "group_id": group_id}),
"application/json"
)
self.assertEqual(response.status_code, 204)
return response
class TestStaffMasqueradeAsStudent(StaffMasqueradeTestCase):
"""
Check for staff being able to masquerade as student.
"""
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_staff_debug_with_masquerade(self):
"""
Tests that staff debug control is not visible when masquerading as a student.
"""
# Verify staff initially can see staff debug
self.verify_staff_debug_present(True)
# Toggle masquerade to student
self.update_masquerade(role='student')
self.verify_staff_debug_present(False)
# Toggle masquerade back to staff
self.update_masquerade(role='staff')
self.verify_staff_debug_present(True)
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_show_answer_for_staff(self):
"""
Tests that "Show Answer" is not visible when masquerading as a student.
"""
# Verify that staff initially can see "Show Answer".
self.verify_show_answer_present(True)
# Toggle masquerade to student
self.update_masquerade(role='student')
self.verify_show_answer_present(False)
# Toggle masquerade back to staff
self.update_masquerade(role='staff')
self.verify_show_answer_present(True)
class TestGetMasqueradingGroupId(StaffMasqueradeTestCase):
"""
Check for staff being able to masquerade as belonging to a group.
"""
def setUp(self):
super(TestGetMasqueradingGroupId, self).setUp()
self.user_partition = UserPartition(
0, 'Test User Partition', '',
[Group(0, 'Group 1'), Group(1, 'Group 2')],
scheme_id='cohort'
)
self.course.user_partitions.append(self.user_partition)
modulestore().update_item(self.course, self.test_user.id)
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_group_masquerade(self):
"""
Tests that a staff member can masquerade as being in a particular group.
"""
# Verify that there is no masquerading group initially
group_id, user_partition_id = get_masquerading_group_info(self.test_user, self.course.id)
self.assertIsNone(group_id)
self.assertIsNone(user_partition_id)
# Install a masquerading group
request = self._create_mock_json_request(
self.test_user,
body='{"role": "student", "user_partition_id": 0, "group_id": 1}'
)
handle_ajax(request, unicode(self.course.id))
setup_masquerade(request, self.test_user, True)
# Verify that the masquerading group is returned
group_id, user_partition_id = get_masquerading_group_info(self.test_user, self.course.id)
self.assertEqual(group_id, 1)
self.assertEqual(user_partition_id, 0)