test_hint_manager.py 8.96 KB
Newer Older
1 2
import json

3
from django.test.client import Client, RequestFactory
4
from django.test.utils import override_settings
5
from mock import patch, MagicMock
6

Calen Pennington committed
7 8
from courseware.models import XModuleUserStateSummaryField
from courseware.tests.factories import UserStateSummaryFactory
9
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
10
import instructor.hint_manager as view
11
from student.tests.factories import UserFactory
12
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
13
from xmodule.modulestore.tests.factories import CourseFactory
14

15

16
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
17 18 19 20 21 22 23
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.
        """
24 25 26 27 28 29 30
        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'
Calen Pennington committed
31 32
        UserStateSummaryFactory.create(field_name='hints',
                              usage_id=self.problem_id,
33 34 35
                              value=json.dumps({'1.0': {'1': ['Hint 1', 2],
                                                        '3': ['Hint 3', 12]},
                                                '2.0': {'4': ['Hint 4', 3]}
36
                                                }))
Calen Pennington committed
37 38
        UserStateSummaryFactory.create(field_name='mod_queue',
                              usage_id=self.problem_id,
39 40
                              value=json.dumps({'2.0': {'2': ['Hint 2', 1]}}))

Calen Pennington committed
41 42
        UserStateSummaryFactory.create(field_name='hint_pk',
                              usage_id=self.problem_id,
43 44 45
                              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.)
46
        view.location_to_problem_name = lambda course_id, loc: "Test problem"
47 48 49 50 51 52

    def test_student_block(self):
        """
        Makes sure that students cannot see the hint management view.
        """
        c = Client()
53
        UserFactory.create(username='student', email='student@edx.org', password='test')
54 55
        c.login(username='student', password='test')
        out = c.get(self.url)
56 57 58 59 60 61 62
        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.
        """
63
        out = self.c.get('/courses/Me/19.002/test_course/hint_manager')
64 65 66
        print out
        self.assertTrue('Hints Awaiting Moderation' in out.content)

67 68
    def test_invalid_field_access(self):
        """
69
        Makes sure that field names other than 'mod_queue' and 'hints' are
70 71 72 73 74 75
        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)

76 77 78 79 80 81 82 83
    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)

84 85 86 87 88 89 90 91 92
    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')
93
        expected = {self.problem_id: [(u'2.0', {u'2': [u'Hint 2', 1]})]}
94 95
        self.assertTrue(out['all_hints'] == expected)

96 97 98 99 100 101 102 103 104
    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')
105 106 107
        expected = {self.problem_id: [('1.0', {'1': ['Hint 1', 2],
                                               '3': ['Hint 3', 12]}),
                                      ('2.0', {'4': ['Hint 4', 3]})
108
                                      ]}
109
        self.assertTrue(out['all_hints'] == expected)
110

111 112 113 114 115 116 117 118 119
    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')
Calen Pennington committed
120
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
121 122 123 124 125 126 127 128 129 130 131
        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')
Calen Pennington committed
132
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
133 134 135 136
        # 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)

137 138 139 140
    def test_addhint(self):
        """
        Check that instructors can add new hints.
        """
141 142 143
        # Because add_hint accesses the xmodule, this test requires a bunch
        # of monkey patching.
        hinter = MagicMock()
144
        hinter.validate_answer = lambda string: True
145

146 147 148 149 150 151
        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.'})
152
        post.user = 'fake user'
153
        with patch('courseware.module_render.get_module', MagicMock(return_value=hinter)):
Calen Pennington committed
154
            with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
155
                view.add_hint(post, self.course_id, 'mod_queue')
Calen Pennington committed
156
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
157 158
        self.assertTrue('3.14' in json.loads(problem_hints))

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    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)):
Calen Pennington committed
175
            with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
176
                view.add_hint(post, self.course_id, 'mod_queue')
Calen Pennington committed
177
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
178 179
        self.assertTrue('fish' not in json.loads(problem_hints))

180 181 182 183 184 185 186 187 188 189
    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')
Calen Pennington committed
190
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
191
        self.assertTrue('2.0' not in json.loads(problem_hints) or len(json.loads(problem_hints)['2.0']) == 0)
Calen Pennington committed
192
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
193 194
        self.assertTrue(json.loads(problem_hints)['2.0']['2'] == ['Hint 2', 1])
        self.assertTrue(len(json.loads(problem_hints)['2.0']) == 2)