test_clone_course.py 6.65 KB
Newer Older
Don Mitchell committed
1 2 3
"""
Unit tests for cloning a course between the same and different module stores.
"""
Ben McMorran committed
4
import json
5

6 7
from django.conf import settings
from mock import Mock, patch
Don Mitchell committed
8
from opaque_keys.edx.locator import CourseLocator
9

Don Mitchell committed
10
from contentstore.tasks import rerun_course
11
from contentstore.tests.utils import CourseTestCase
Don Mitchell committed
12
from course_action_state.managers import CourseRerunUIStateManager
13 14
from course_action_state.models import CourseRerunState
from student.auth import has_course_author_access
15 16
from xmodule.contentstore.content import StaticContent
from xmodule.contentstore.django import contentstore
17
from xmodule.modulestore import EdxJSONEncoder, ModuleStoreEnum
18 19 20
from xmodule.modulestore.tests.factories import CourseFactory

TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
Don Mitchell committed
21 22 23 24 25 26 27 28 29 30 31 32 33


class CloneCourseTest(CourseTestCase):
    """
    Unit tests for cloning a course
    """
    def test_clone_course(self):
        """Tests cloning of a course as follows: XML -> Mongo (+ data) -> Mongo -> Split -> Split"""
        # 1. import and populate test toy course
        mongo_course1_id = self.import_and_populate_course()

        # 2. clone course (mongo -> mongo)
        # TODO - This is currently failing since clone_course doesn't handle Private content - fails on Publish
34 35 36 37 38 39 40
        # mongo_course2_id = SlashSeparatedCourseKey('edX2', 'toy2', '2013_Fall')
        # self.store.clone_course(mongo_course1_id, mongo_course2_id, self.user.id)
        # self.assertCoursesEqual(mongo_course1_id, mongo_course2_id)
        # self.check_populated_course(mongo_course2_id)

        # NOTE: When the code above is uncommented this can be removed.
        mongo_course2_id = mongo_course1_id
Don Mitchell committed
41 42

        # 3. clone course (mongo -> split)
43
        with self.store.default_store(ModuleStoreEnum.Type.split):
Don Mitchell committed
44
            split_course3_id = CourseLocator(
Don Mitchell committed
45
                org="edx3", course="split3", run="2013_Fall"
Don Mitchell committed
46 47 48 49 50 51
            )
            self.store.clone_course(mongo_course2_id, split_course3_id, self.user.id)
            self.assertCoursesEqual(mongo_course2_id, split_course3_id)

            # 4. clone course (split -> split)
            split_course4_id = CourseLocator(
Don Mitchell committed
52
                org="edx4", course="split4", run="2013_Fall"
Don Mitchell committed
53 54 55
            )
            self.store.clone_course(split_course3_id, split_course4_id, self.user.id)
            self.assertCoursesEqual(split_course3_id, split_course4_id)
Don Mitchell committed
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    def test_space_in_asset_name_for_rerun_course(self):
        """
        Tests check the scenario where one course which has an asset with percentage(%) in its
        name, it should re-run successfully.
        """
        org = 'edX'
        course_number = 'CS101'
        course_run = '2015_Q1'
        display_name = 'rerun'
        fields = {'display_name': display_name}
        course_assets = set([u'subs_Introduction%20To%20New.srt.sjson'], )

        # Create a course using split modulestore
        course = CourseFactory.create(
            org=org,
            number=course_number,
            run=course_run,
            display_name=display_name,
            default_store=ModuleStoreEnum.Type.split
        )

        # add an asset
        asset_key = course.id.make_asset_key('asset', 'subs_Introduction%20To%20New.srt.sjson')
        content = StaticContent(
            asset_key, 'Dummy assert', 'application/json', 'dummy data',
        )
        contentstore().save(content)

        # Get & verify all assets of the course
        assets, count = contentstore().get_all_content_for_course(course.id)
        self.assertEqual(count, 1)
        self.assertEqual(set([asset['asset_key'].block_id for asset in assets]), course_assets)

        # rerun from split into split
        split_rerun_id = CourseLocator(org=org, course=course_number, run="2012_Q2")
        CourseRerunState.objects.initiated(course.id, split_rerun_id, self.user, fields['display_name'])
        result = rerun_course.delay(
            unicode(course.id),
            unicode(split_rerun_id),
            self.user.id,
            json.dumps(fields, cls=EdxJSONEncoder)
        )

        # Check if re-run was successful
        self.assertEqual(result.get(), "succeeded")
        rerun_state = CourseRerunState.objects.find_first(course_key=split_rerun_id)
        self.assertEqual(rerun_state.state, CourseRerunUIStateManager.State.SUCCEEDED)

Don Mitchell committed
105 106 107 108 109 110 111 112 113 114 115 116 117
    def test_rerun_course(self):
        """
        Unit tests for :meth: `contentstore.tasks.rerun_course`
        """
        mongo_course1_id = self.import_and_populate_course()

        # rerun from mongo into split
        split_course3_id = CourseLocator(
            org="edx3", course="split3", run="rerun_test"
        )
        # Mark the action as initiated
        fields = {'display_name': 'rerun'}
        CourseRerunState.objects.initiated(mongo_course1_id, split_course3_id, self.user, fields['display_name'])
Ben McMorran committed
118 119
        result = rerun_course.delay(unicode(mongo_course1_id), unicode(split_course3_id), self.user.id,
                                    json.dumps(fields, cls=EdxJSONEncoder))
Don Mitchell committed
120
        self.assertEqual(result.get(), "succeeded")
121
        self.assertTrue(has_course_author_access(self.user, split_course3_id), "Didn't grant access")
Don Mitchell committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
        rerun_state = CourseRerunState.objects.find_first(course_key=split_course3_id)
        self.assertEqual(rerun_state.state, CourseRerunUIStateManager.State.SUCCEEDED)

        # try creating rerunning again to same name and ensure it generates error
        result = rerun_course.delay(unicode(mongo_course1_id), unicode(split_course3_id), self.user.id)
        self.assertEqual(result.get(), "duplicate course")
        # the below will raise an exception if the record doesn't exist
        CourseRerunState.objects.find_first(
            course_key=split_course3_id,
            state=CourseRerunUIStateManager.State.FAILED
        )

        # try to hit the generic exception catch
        with patch('xmodule.modulestore.split_mongo.mongo_connection.MongoConnection.insert_course_index', Mock(side_effect=Exception)):
            split_course4_id = CourseLocator(org="edx3", course="split3", run="rerun_fail")
            fields = {'display_name': 'total failure'}
            CourseRerunState.objects.initiated(split_course3_id, split_course4_id, self.user, fields['display_name'])
Ben McMorran committed
139 140
            result = rerun_course.delay(unicode(split_course3_id), unicode(split_course4_id), self.user.id,
                                        json.dumps(fields, cls=EdxJSONEncoder))
Don Mitchell committed
141 142 143 144 145 146
            self.assertIn("exception: ", result.get())
            self.assertIsNone(self.store.get_course(split_course4_id), "Didn't delete course after error")
            CourseRerunState.objects.find_first(
                course_key=split_course4_id,
                state=CourseRerunUIStateManager.State.FAILED
            )