195 lines
9.0 KiB
Python
195 lines
9.0 KiB
Python
import json
|
|
|
|
from django.test.client import Client, RequestFactory
|
|
from django.test.utils import override_settings
|
|
from mock import patch, MagicMock
|
|
|
|
from courseware.models import XModuleUserStateSummaryField
|
|
from courseware.tests.factories import UserStateSummaryFactory
|
|
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
|
|
import instructor.hint_manager as view
|
|
from student.tests.factories import UserFactory
|
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
|
from xmodule.modulestore.tests.factories import CourseFactory
|
|
|
|
|
|
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
|
|
class HintManagerTest(ModuleStoreTestCase):
|
|
|
|
def setUp(self):
|
|
"""
|
|
Makes a course, which will be the same for all tests.
|
|
Set up mako middleware, which is necessary for template rendering to happen.
|
|
"""
|
|
self.course = CourseFactory.create(org='Me', number='19.002', display_name='test_course')
|
|
self.url = '/courses/Me/19.002/test_course/hint_manager'
|
|
self.user = UserFactory.create(username='robot', email='robot@edx.org', password='test', is_staff=True)
|
|
self.c = Client()
|
|
self.c.login(username='robot', password='test')
|
|
self.problem_id = 'i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_001'
|
|
self.course_id = 'Me/19.002/test_course'
|
|
UserStateSummaryFactory.create(field_name='hints',
|
|
usage_id=self.problem_id,
|
|
value=json.dumps({'1.0': {'1': ['Hint 1', 2],
|
|
'3': ['Hint 3', 12]},
|
|
'2.0': {'4': ['Hint 4', 3]}
|
|
}))
|
|
UserStateSummaryFactory.create(field_name='mod_queue',
|
|
usage_id=self.problem_id,
|
|
value=json.dumps({'2.0': {'2': ['Hint 2', 1]}}))
|
|
|
|
UserStateSummaryFactory.create(field_name='hint_pk',
|
|
usage_id=self.problem_id,
|
|
value=5)
|
|
# Mock out location_to_problem_name, which ordinarily accesses the modulestore.
|
|
# (I can't figure out how to get fake structures into the modulestore.)
|
|
view.location_to_problem_name = lambda course_id, loc: "Test problem"
|
|
|
|
def test_student_block(self):
|
|
"""
|
|
Makes sure that students cannot see the hint management view.
|
|
"""
|
|
c = Client()
|
|
UserFactory.create(username='student', email='student@edx.org', password='test')
|
|
c.login(username='student', password='test')
|
|
out = c.get(self.url)
|
|
print out
|
|
self.assertTrue('Sorry, but students are not allowed to access the hint manager!' in out.content)
|
|
|
|
def test_staff_access(self):
|
|
"""
|
|
Makes sure that staff can access the hint management view.
|
|
"""
|
|
out = self.c.get('/courses/Me/19.002/test_course/hint_manager')
|
|
print out
|
|
self.assertTrue('Hints Awaiting Moderation' in out.content)
|
|
|
|
def test_invalid_field_access(self):
|
|
"""
|
|
Makes sure that field names other than 'mod_queue' and 'hints' are
|
|
rejected.
|
|
"""
|
|
out = self.c.post(self.url, {'op': 'delete hints', 'field': 'all your private data'})
|
|
print out
|
|
self.assertTrue('an invalid field was accessed' in out.content)
|
|
|
|
def test_switchfields(self):
|
|
"""
|
|
Checks that the op: 'switch fields' POST request works.
|
|
"""
|
|
out = self.c.post(self.url, {'op': 'switch fields', 'field': 'mod_queue'})
|
|
print out
|
|
self.assertTrue('Hint 2' in out.content)
|
|
|
|
def test_gethints(self):
|
|
"""
|
|
Checks that gethints returns the right data.
|
|
"""
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'mod_queue'})
|
|
out = view.get_hints(post, self.course_id, 'mod_queue')
|
|
print out
|
|
self.assertTrue(out['other_field'] == 'hints')
|
|
expected = {self.problem_id: [(u'2.0', {u'2': [u'Hint 2', 1]})]}
|
|
self.assertTrue(out['all_hints'] == expected)
|
|
|
|
def test_gethints_other(self):
|
|
"""
|
|
Same as above, with hints instead of mod_queue
|
|
"""
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'hints'})
|
|
out = view.get_hints(post, self.course_id, 'hints')
|
|
print out
|
|
self.assertTrue(out['other_field'] == 'mod_queue')
|
|
expected = {self.problem_id: [('1.0', {'1': ['Hint 1', 2],
|
|
'3': ['Hint 3', 12]}),
|
|
('2.0', {'4': ['Hint 4', 3]})
|
|
]}
|
|
self.assertTrue(out['all_hints'] == expected)
|
|
|
|
def test_deletehints(self):
|
|
"""
|
|
Checks that delete_hints deletes the right stuff.
|
|
"""
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'hints',
|
|
'op': 'delete hints',
|
|
1: [self.problem_id, '1.0', '1']})
|
|
view.delete_hints(post, self.course_id, 'hints')
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
|
|
self.assertTrue('1' not in json.loads(problem_hints)['1.0'])
|
|
|
|
def test_changevotes(self):
|
|
"""
|
|
Checks that vote changing works.
|
|
"""
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'hints',
|
|
'op': 'change votes',
|
|
1: [self.problem_id, '1.0', '1', 5]})
|
|
view.change_votes(post, self.course_id, 'hints')
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
|
|
# hints[answer][hint_pk (string)] = [hint text, vote count]
|
|
print json.loads(problem_hints)['1.0']['1']
|
|
self.assertTrue(json.loads(problem_hints)['1.0']['1'][1] == 5)
|
|
|
|
def test_addhint(self):
|
|
"""
|
|
Check that instructors can add new hints.
|
|
"""
|
|
# Because add_hint accesses the xmodule, this test requires a bunch
|
|
# of monkey patching.
|
|
hinter = MagicMock()
|
|
hinter.validate_answer = lambda string: True
|
|
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'mod_queue',
|
|
'op': 'add hint',
|
|
'problem': self.problem_id,
|
|
'answer': '3.14',
|
|
'hint': 'This is a new hint.'})
|
|
post.user = 'fake user'
|
|
with patch('courseware.module_render.get_module', MagicMock(return_value=hinter)):
|
|
with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
|
|
view.add_hint(post, self.course_id, 'mod_queue')
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
|
|
self.assertTrue('3.14' in json.loads(problem_hints))
|
|
|
|
def test_addbadhint(self):
|
|
"""
|
|
Check that instructors cannot add hints with unparsable answers.
|
|
"""
|
|
# Patching.
|
|
hinter = MagicMock()
|
|
hinter.validate_answer = lambda string: False
|
|
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'mod_queue',
|
|
'op': 'add hint',
|
|
'problem': self.problem_id,
|
|
'answer': 'fish',
|
|
'hint': 'This is a new hint.'})
|
|
post.user = 'fake user'
|
|
with patch('courseware.module_render.get_module', MagicMock(return_value=hinter)):
|
|
with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
|
|
view.add_hint(post, self.course_id, 'mod_queue')
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
|
|
self.assertTrue('fish' not in json.loads(problem_hints))
|
|
|
|
def test_approve(self):
|
|
"""
|
|
Check that instructors can approve hints. (Move them
|
|
from the mod_queue to the hints.)
|
|
"""
|
|
request = RequestFactory()
|
|
post = request.post(self.url, {'field': 'mod_queue',
|
|
'op': 'approve',
|
|
1: [self.problem_id, '2.0', '2']})
|
|
view.approve(post, self.course_id, 'mod_queue')
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
|
|
self.assertTrue('2.0' not in json.loads(problem_hints) or len(json.loads(problem_hints)['2.0']) == 0)
|
|
problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
|
|
self.assertTrue(json.loads(problem_hints)['2.0']['2'] == ['Hint 2', 1])
|
|
self.assertTrue(len(json.loads(problem_hints)['2.0']) == 2)
|