test_hint_manager.py 8.93 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 xmodule.modulestore.tests.django_utils import TEST_DATA_MOCK_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
# pylint: disable=missing-docstring
16

muhammad-ammar committed
17

18 19 20 21 22 23 24
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.
        """
25 26
        super(HintManagerTest, self).setUp()

27 28 29 30 31
        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')
32 33
        self.course_id = self.course.id
        self.problem_id = self.course_id.make_usage_key('crowdsource_hinter', 'crowdsource_hinter_001')
34 35 36 37 38 39 40 41 42 43 44 45 46
        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]}})
        )
47

48 49 50 51 52
        UserStateSummaryFactory.create(
            field_name='hint_pk',
            usage_id=self.problem_id,
            value=5
        )
53 54
        # Mock out location_to_problem_name, which ordinarily accesses the modulestore.
        # (I can't figure out how to get fake structures into the modulestore.)
55
        view.location_to_problem_name = lambda course_id, loc: "Test problem"
56 57 58 59 60 61

    def test_student_block(self):
        """
        Makes sure that students cannot see the hint management view.
        """
        c = Client()
62
        UserFactory.create(username='student', email='student@edx.org', password='test')
63 64
        c.login(username='student', password='test')
        out = c.get(self.url)
65 66 67 68 69 70 71
        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.
        """
72
        out = self.c.get(self.url)
73 74 75
        print out
        self.assertTrue('Hints Awaiting Moderation' in out.content)

76 77
    def test_invalid_field_access(self):
        """
78
        Makes sure that field names other than 'mod_queue' and 'hints' are
79 80 81 82 83 84
        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)

85 86 87 88 89 90 91 92
    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)

93 94 95 96 97 98 99 100 101
    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')
102
        expected = {self.problem_id: [(u'2.0', {u'2': [u'Hint 2', 1]})]}
103 104
        self.assertTrue(out['all_hints'] == expected)

105 106 107 108 109 110 111 112 113
    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')
114 115 116
        expected = {self.problem_id: [('1.0', {'1': ['Hint 1', 2],
                                               '3': ['Hint 3', 12]}),
                                      ('2.0', {'4': ['Hint 4', 3]})
117
                                      ]}
118
        self.assertTrue(out['all_hints'] == expected)
119

120 121 122 123 124 125 126
    def test_deletehints(self):
        """
        Checks that delete_hints deletes the right stuff.
        """
        request = RequestFactory()
        post = request.post(self.url, {'field': 'hints',
                                       'op': 'delete hints',
127
                                       1: [self.problem_id.to_deprecated_string(), '1.0', '1']})
128
        view.delete_hints(post, self.course_id, 'hints')
Calen Pennington committed
129
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
130 131 132 133 134 135 136 137 138
        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',
139
                                       1: [self.problem_id.to_deprecated_string(), '1.0', '1', 5]})
140
        view.change_votes(post, self.course_id, 'hints')
Calen Pennington committed
141
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
142 143 144 145
        # 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)

146 147 148 149
    def test_addhint(self):
        """
        Check that instructors can add new hints.
        """
150 151 152
        # Because add_hint accesses the xmodule, this test requires a bunch
        # of monkey patching.
        hinter = MagicMock()
153
        hinter.validate_answer = lambda string: True
154

155 156 157
        request = RequestFactory()
        post = request.post(self.url, {'field': 'mod_queue',
                                       'op': 'add hint',
158
                                       'problem': self.problem_id.to_deprecated_string(),
159 160
                                       'answer': '3.14',
                                       'hint': 'This is a new hint.'})
161
        post.user = 'fake user'
162
        with patch('courseware.module_render.get_module', MagicMock(return_value=hinter)):
Calen Pennington committed
163
            with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
164
                view.add_hint(post, self.course_id, 'mod_queue')
Calen Pennington committed
165
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
166 167
        self.assertTrue('3.14' in json.loads(problem_hints))

168 169 170 171 172 173 174 175 176 177 178
    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',
179
                                       'problem': self.problem_id.to_deprecated_string(),
180 181 182 183
                                       '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
184
            with patch('courseware.model_data.FieldDataCache', MagicMock(return_value=None)):
185
                view.add_hint(post, self.course_id, 'mod_queue')
Calen Pennington committed
186
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
187 188
        self.assertTrue('fish' not in json.loads(problem_hints))

189 190 191 192 193 194 195 196
    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',
197
                                       1: [self.problem_id.to_deprecated_string(), '2.0', '2']})
198
        view.approve(post, self.course_id, 'mod_queue')
Calen Pennington committed
199
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='mod_queue', usage_id=self.problem_id).value
200
        self.assertTrue('2.0' not in json.loads(problem_hints) or len(json.loads(problem_hints)['2.0']) == 0)
Calen Pennington committed
201
        problem_hints = XModuleUserStateSummaryField.objects.get(field_name='hints', usage_id=self.problem_id).value
202 203
        self.assertTrue(json.loads(problem_hints)['2.0']['2'] == ['Hint 2', 1])
        self.assertTrue(len(json.loads(problem_hints)['2.0']) == 2)