tests.py 6.64 KB
Newer Older
1 2 3
"""
Test for LMS courseware app.
"""
lapentab committed
4
import mock
5 6
from mock import Mock
from unittest import TestCase
7
from django.core.urlresolvers import reverse
8
from django.test.utils import override_settings
9

10 11
from textwrap import dedent

12
from xmodule.error_module import ErrorDescriptor
13
from xmodule.modulestore.django import modulestore
14
from opaque_keys.edx.locations import SlashSeparatedCourseKey
15
from xmodule.modulestore.xml_importer import import_from_xml
16
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
Victor Shnayder committed
17

18 19
from courseware.tests.helpers import LoginEnrollmentTestCase
from courseware.tests.modulestore_config import TEST_DATA_DIR, \
20
    TEST_DATA_MONGO_MODULESTORE, \
21
    TEST_DATA_MIXED_MODULESTORE
22
from lms.lib.xblock.field_data import LmsFieldData
23 24 25 26 27 28 29 30


class ActivateLoginTest(LoginEnrollmentTestCase):
    """
    Test logging in and logging out.
    """
    def setUp(self):
        self.setup_user()
Victor Shnayder committed
31

32 33 34
    def test_activate_login(self):
        """
        Test login -- the setup function does all the work.
Victor Shnayder committed
35
        """
36 37 38
        pass

    def test_logout(self):
Victor Shnayder committed
39
        """
40
        Test logout -- setup function does login.
Victor Shnayder committed
41
        """
42 43 44 45 46 47 48
        self.logout()


class PageLoaderTestCase(LoginEnrollmentTestCase):
    """
    Base class that adds a function to load all pages in a modulestore.
    """
49

50
    def check_all_pages_load(self, course_key):
51
        """
52 53
        Assert that all pages in the course load correctly.
        `course_id` is the ID of the course to check.
54
        """
55 56 57 58

        store = modulestore()

        # Enroll in the course before trying to access pages
59
        course = store.get_course(course_key)
60 61 62
        self.enroll(course, True)

        # Search for items in the course
63
        items = store.get_items(course_key)
64 65 66 67

        if len(items) < 1:
            self.fail('Could not retrieve any items from course')

68 69
        # Try to load each item in the course
        for descriptor in items:
70

71 72
            if descriptor.location.category == 'about':
                self._assert_loads('about_course',
73
                                   {'course_id': course_key.to_deprecated_string()},
74
                                   descriptor)
75

76
            elif descriptor.location.category == 'static_tab':
77
                kwargs = {'course_id': course_key.to_deprecated_string(),
78 79
                          'tab_slug': descriptor.location.name}
                self._assert_loads('static_tab', kwargs, descriptor)
80

81
            elif descriptor.location.category == 'course_info':
82
                self._assert_loads('info', {'course_id': course_key.to_deprecated_string()},
83
                                   descriptor)
84

85
            else:
86

87
                kwargs = {'course_id': course_key.to_deprecated_string(),
88
                          'location': descriptor.location.to_deprecated_string()}
89

90 91 92
                self._assert_loads('jump_to', kwargs, descriptor,
                                   expect_redirect=True,
                                   check_content=True)
93 94 95 96 97 98 99 100 101

    def _assert_loads(self, django_url, kwargs, descriptor,
                      expect_redirect=False,
                      check_content=False):
        """
        Assert that the url loads correctly.
        If expect_redirect, then also check that we were redirected.
        If check_content, then check that we don't get
        an error message about unavailable modules.
102
        """
Victor Shnayder committed
103

104 105
        url = reverse(django_url, kwargs=kwargs)
        response = self.client.get(url, follow=True)
Will Daly committed
106

107 108
        if response.status_code != 200:
            self.fail('Status %d for page %s' %
109
                      (response.status_code, descriptor.location))
Will Daly committed
110

111 112
        if expect_redirect:
            self.assertEqual(response.redirect_chain[0][1], 302)
Will Daly committed
113

114
        if check_content:
115 116
            self.assertNotContains(response, "this module is temporarily unavailable")
            self.assertNotIsInstance(descriptor, ErrorDescriptor)
117

118

119 120
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestXmlCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase):
121 122 123
    """
    Check that all pages in test courses load properly from XML.
    """
124 125

    def setUp(self):
126
        super(TestXmlCoursesLoad, self).setUp()
127
        self.setup_user()
128

129
    def test_toy_course_loads(self):
130 131 132
        # Load one of the XML based courses
        # Our test mapping rules allow the MixedModuleStore
        # to load this course from XML, not Mongo.
133
        self.check_all_pages_load(SlashSeparatedCourseKey('edX', 'toy', '2012_Fall'))
134 135


136
class TestMongoCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase):
137 138 139
    """
    Check that all pages in test courses load properly from Mongo.
    """
140

141
    def setUp(self):
142
        super(TestMongoCoursesLoad, self).setUp()
143
        self.setup_user()
144

145 146
        # Import the toy course
        import_from_xml(self.store, self.user.id, TEST_DATA_DIR, ['toy'])
147

lapentab committed
148 149
    @mock.patch('xmodule.course_module.requests.get')
    def test_toy_textbooks_loads(self, mock_get):
lapentab committed
150 151 152 153 154 155
        mock_get.return_value.text = dedent("""
            <?xml version="1.0"?><table_of_contents>
            <entry page="5" page_label="ii" name="Table of Contents"/>
            </table_of_contents>
        """).strip()

156
        location = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall').make_usage_key('course', '2012_Fall')
157
        course = self.store.get_item(location)
158
        self.assertGreater(len(course.textbooks), 0)
159

lapentab committed
160

Will Daly committed
161
class TestDraftModuleStore(ModuleStoreTestCase):
162 163
    def test_get_items_with_course_items(self):
        store = modulestore()
164

165
        # fix was to allow get_items() to take the course_id parameter
166
        store.get_items(SlashSeparatedCourseKey('abc', 'def', 'ghi'), qualifiers={'category': 'vertical'})
167

168 169 170
        # test success is just getting through the above statement.
        # The bug was that 'course_id' argument was
        # not allowed to be passed in (i.e. was throwing exception)
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191


class TestLmsFieldData(TestCase):
    """
    Tests of the LmsFieldData class
    """
    def test_lms_field_data_wont_nest(self):
        # Verify that if an LmsFieldData is passed into LmsFieldData as the
        # authored_data, that it doesn't produced a nested field data.
        #
        # This fixes a bug where re-use of the same descriptor for many modules
        # would cause more and more nesting, until the recursion depth would be
        # reached on any attribute access

        # pylint: disable=protected-access
        base_authored = Mock()
        base_student = Mock()
        first_level = LmsFieldData(base_authored, base_student)
        second_level = LmsFieldData(first_level, base_student)
        self.assertEquals(second_level._authored_data, first_level._authored_data)
        self.assertNotIsInstance(second_level._authored_data, LmsFieldData)