Ejemplo n.º 1
0
    def initdb(cls):
        # connect to the db
        doc_store_config = {
            'host': HOST,
            'db': DB,
            'collection': COLLECTION,
        }
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        content_store = MongoContentStore(HOST, DB)
        #
        # Also test draft store imports
        #
        draft_store = DraftModuleStore(
            content_store,
            doc_store_config,
            FS_ROOT,
            RENDER_TEMPLATE,
            default_class=DEFAULT_CLASS,
            branch_setting_func=lambda: ModuleStoreEnum.Branch.draft_preferred)
        import_from_xml(draft_store,
                        999,
                        DATA_DIR,
                        cls.courses,
                        static_content_store=content_store)

        # also test a course with no importing of static content
        import_from_xml(draft_store,
                        999,
                        DATA_DIR, ['test_import_course'],
                        static_content_store=content_store,
                        do_import_static=False,
                        verbose=True)

        return content_store, draft_store
Ejemplo n.º 2
0
    def load_test_import_course(self,
                                target_course_id=None,
                                create_new_course_if_not_present=False):
        '''
        Load the standard course used to test imports
        (for do_import_static=False behavior).
        '''
        content_store = contentstore()
        module_store = modulestore()
        import_from_xml(
            module_store,
            self.user.id,
            TEST_DATA_DIR,
            ['test_import_course'],
            static_content_store=content_store,
            do_import_static=False,
            verbose=True,
            target_course_id=target_course_id,
            create_new_course_if_not_present=create_new_course_if_not_present,
        )
        course_id = module_store.make_course_key('edX', 'test_import_course',
                                                 '2012_Fall')
        course = module_store.get_course(course_id)
        self.assertIsNotNone(course)

        return module_store, content_store, course
Ejemplo n.º 3
0
    def setUp(self):
        super(TestMongoCoursesLoad, self).setUp()
        self.setup_user()

        # Import the toy course into a Mongo-backed modulestore
        self.store = modulestore()
        import_from_xml(self.store, TEST_DATA_DIR, ['toy'])
Ejemplo n.º 4
0
    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()
        store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)  # pylint: disable=protected-access

        self.course_key = store.make_course_key('edX', 'toy', '2012_Fall')

        import_from_xml(
            store, self.user.id, TEST_DATA_DIR, ['toy'],
            static_content_store=self.contentstore, verbose=True
        )

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = unicode(self.locked_asset)
        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = unicode(self.unlocked_asset)
        self.length_unlocked = self.contentstore.get_attr(self.unlocked_asset, 'length')
Ejemplo n.º 5
0
    def check_components_on_page(self, component_types, expected_types):
        """
        Ensure that the right types end up on the page.

        component_types is the list of advanced components.

        expected_types is the list of elements that should appear on the page.

        expected_types and component_types should be similar, but not
        exactly the same -- for example, 'videoalpha' in
        component_types should cause 'Video Alpha' to be present.
        """
        store = modulestore('direct')
        import_from_xml(store, 'common/test/data/', ['simple'])

        course = store.get_item(Location(
            ['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
                                depth=None)

        course.advanced_modules = component_types

        store.update_metadata(course.location, own_metadata(course))

        # just pick one vertical
        descriptor = store.get_items(
            Location('i4x', 'edX', 'simple', 'vertical', None, None))[0]

        resp = self.client.get(
            reverse('edit_unit',
                    kwargs={'location': descriptor.location.url()}))
        self.assertEqual(resp.status_code, 200)

        for expected in expected_types:
            self.assertIn(expected, resp.content)
Ejemplo n.º 6
0
    def test_toy_textbooks_loads(self):
        module_store = modulestore()
        import_from_xml(module_store, TEST_DATA_DIR, ['toy'])

        course = module_store.get_item(Location(['i4x', 'edX', 'toy', 'course', '2012_Fall', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 7
0
    def test_prefetch_children(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        location = CourseDescriptor.id_to_location(
            'edX/full/6.002_Spring_2012')

        wrapper = MongoCollectionFindWrapper(module_store.collection.find)
        module_store.collection.find = wrapper.find
        course = module_store.get_item(location, depth=2)

        # make sure we haven't done too many round trips to DB
        # note we say 4 round trips here for 1) the course, 2 & 3) for the chapters and sequentials, and
        # 4) because of the RT due to calculating the inherited metadata
        self.assertEqual(wrapper.counter, 4)

        # make sure we pre-fetched a known sequential which should be at depth=2
        self.assertTrue(
            Location([
                'i4x', 'edX', 'full', 'sequential',
                'Administrivia_and_Circuit_Elements', None
            ]) in course.system.module_data)

        # make sure we don't have a specific vertical which should be at depth=3
        self.assertFalse(
            Location(['i4x', 'edX', 'full', 'vertical', 'vertical_58', None])
            in course.system.module_data)
Ejemplo n.º 8
0
    def test_static_tab_reordering(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        course = module_store.get_item(
            Location(
                ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        # reverse the ordering
        reverse_tabs = []
        for tab in course.tabs:
            if tab['type'] == 'static_tab':
                reverse_tabs.insert(
                    0, 'i4x://edX/full/static_tab/{0}'.format(tab['url_slug']))

        self.client.post(reverse('reorder_static_tabs'),
                         json.dumps({'tabs': reverse_tabs}),
                         "application/json")

        course = module_store.get_item(
            Location(
                ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        # compare to make sure that the tabs information is in the expected order after the server call
        course_tabs = []
        for tab in course.tabs:
            if tab['type'] == 'static_tab':
                course_tabs.append('i4x://edX/full/static_tab/{0}'.format(
                    tab['url_slug']))

        self.assertEqual(reverse_tabs, course_tabs)
Ejemplo n.º 9
0
    def test_get_depth_with_drafts(self):
        import_from_xml(modulestore('direct'), 'common/test/data/', ['simple'])

        course = modulestore('draft').get_item(Location(
            ['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
                                               depth=None)

        # make sure no draft items have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 0)

        problem = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'problem', 'ps01-simple', None]))

        # put into draft
        modulestore('draft').clone_item(problem.location, problem.location)

        # make sure we can query that item and verify that it is a draft
        draft_problem = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'problem', 'ps01-simple', None]))
        self.assertTrue(getattr(draft_problem, 'is_draft', False))

        #now requery with depth
        course = modulestore('draft').get_item(Location(
            ['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
                                               depth=None)

        # make sure just one draft item have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 1)
Ejemplo n.º 10
0
    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(
            modulestore(), self.user.id, 'common/test/data/', ['toy'],
            static_content_store=self.contentstore, verbose=True
        )

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()
        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()
        self.length_unlocked = self.contentstore.get_attr(self.unlocked_asset, 'length')
Ejemplo n.º 11
0
    def initdb():
        # connect to the db
        doc_store_config = {
            'host': HOST,
            'db': DB,
            'collection': COLLECTION,
        }
        store = MongoModuleStore(doc_store_config, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        content_store = MongoContentStore(HOST, DB)
        #
        # Also test draft store imports
        #
        draft_store = DraftModuleStore(doc_store_config, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
        # Explicitly list the courses to load (don't want the big one)
        courses = ['toy', 'simple', 'simple_with_draft', 'test_unicode']
        import_from_xml(store, DATA_DIR, courses, draft_store=draft_store, static_content_store=content_store)

        # also test a course with no importing of static content
        import_from_xml(
            store,
            DATA_DIR,
            ['test_import_course'],
            static_content_store=content_store,
            do_import_static=False,
            verbose=True
        )

        return store, content_store, draft_store
Ejemplo n.º 12
0
    def test_update_modulestore_signal_did_fire(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        try:
            module_store.modulestore_update_signal = Signal(
                providing_args=['modulestore', 'course_id', 'location'])

            self.got_signal = False

            def _signal_hander(modulestore=None,
                               course_id=None,
                               location=None,
                               **kwargs):
                self.got_signal = True

            module_store.modulestore_update_signal.connect(_signal_hander)

            new_component_location = Location('i4x', 'edX', 'full', 'html',
                                              'new_component')
            source_template_location = Location('i4x', 'edx', 'templates',
                                                'html', 'Blank_HTML_Page')

            # crate a new module
            module_store.clone_item(source_template_location,
                                    new_component_location)

        finally:
            module_store.modulestore_update_signal = None

        self.assertTrue(self.got_signal)
Ejemplo n.º 13
0
    def initdb():
        # connect to the db
        doc_store_config = {
            'host': HOST,
            'db': DB,
            'collection': COLLECTION,
        }
        store = MongoModuleStore(doc_store_config,
                                 FS_ROOT,
                                 RENDER_TEMPLATE,
                                 default_class=DEFAULT_CLASS)
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        content_store = MongoContentStore(HOST, DB)
        #
        # Also test draft store imports
        #
        draft_store = DraftModuleStore(doc_store_config,
                                       FS_ROOT,
                                       RENDER_TEMPLATE,
                                       default_class=DEFAULT_CLASS)
        import_from_xml(store,
                        DATA_DIR,
                        TestMongoModuleStore.courses,
                        draft_store=draft_store,
                        static_content_store=content_store)

        # also test a course with no importing of static content
        import_from_xml(store,
                        DATA_DIR, ['test_import_course'],
                        static_content_store=content_store,
                        do_import_static=False,
                        verbose=True)

        return store, content_store, draft_store
    def _assert_import(self, course_dir, expected_xblock_loc, expected_field_val, has_draft=False):
        """
        Import a course from XML, then verify that the XBlock was loaded
        with the correct field value.

        Args:
            course_dir (str): The name of the course directory (relative to the test data directory)
            expected_xblock_loc (str): The location of the XBlock in the course.
            expected_field_val (str): The expected value of the XBlock's test field.

        Kwargs:
            has_draft (bool): If true, check that a draft of the XBlock exists with
                the expected field value set.

        """
        import_from_xml(
            self.store, 'common/test/data', [course_dir],
            draft_store=self.draft_store
        )

        xblock = self.store.get_item(expected_xblock_loc)
        self.assertTrue(isinstance(xblock, StubXBlock))
        self.assertEqual(xblock.test_field, expected_field_val)

        if has_draft:
            draft_xblock = self.draft_store.get_item(expected_xblock_loc)
            self.assertTrue(isinstance(draft_xblock, StubXBlock))
            self.assertEqual(draft_xblock.test_field, expected_field_val)
Ejemplo n.º 15
0
    def test_get_depth_with_drafts(self):
        import_from_xml(modulestore('direct'), 'common/test/data/', ['simple'])

        course = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
            depth=None
        )

        # make sure no draft items have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 0)

        problem = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'problem', 'ps01-simple', None])
        )

        # put into draft
        modulestore('draft').clone_item(problem.location, problem.location)

        # make sure we can query that item and verify that it is a draft
        draft_problem = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'problem', 'ps01-simple', None])
        )
        self.assertTrue(getattr(draft_problem, 'is_draft', False))

        #now requery with depth
        course = modulestore('draft').get_item(
            Location(['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
            depth=None
        )

        # make sure just one draft item have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 1)
Ejemplo n.º 16
0
    def check_components_on_page(self, component_types, expected_types):
        """
        Ensure that the right types end up on the page.

        component_types is the list of advanced components.

        expected_types is the list of elements that should appear on the page.

        expected_types and component_types should be similar, but not
        exactly the same -- for example, 'videoalpha' in
        component_types should cause 'Video Alpha' to be present.
        """
        store = modulestore('direct')
        import_from_xml(store, 'common/test/data/', ['simple'])

        course = store.get_item(Location(['i4x', 'edX', 'simple',
                                          'course', '2012_Fall', None]), depth=None)

        course.advanced_modules = component_types

        store.update_metadata(course.location, own_metadata(course))

        # just pick one vertical
        descriptor = store.get_items(Location('i4x', 'edX', 'simple', 'vertical', None, None))[0]

        resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()}))
        self.assertEqual(resp.status_code, 200)

        for expected in expected_types:
            self.assertIn(expected, resp.content)
Ejemplo n.º 17
0
    def initdb(cls):
        # connect to the db
        doc_store_config = {"host": HOST, "port": PORT, "db": DB, "collection": COLLECTION}
        cls.add_asset_collection(doc_store_config)

        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        content_store = MongoContentStore(HOST, DB, port=PORT)
        #
        # Also test draft store imports
        #
        draft_store = DraftModuleStore(
            content_store,
            doc_store_config,
            FS_ROOT,
            RENDER_TEMPLATE,
            default_class=DEFAULT_CLASS,
            branch_setting_func=lambda: ModuleStoreEnum.Branch.draft_preferred,
            xblock_mixins=(EditInfoMixin,),
        )
        import_from_xml(draft_store, 999, DATA_DIR, cls.courses, static_content_store=content_store)

        # also test a course with no importing of static content
        import_from_xml(
            draft_store,
            999,
            DATA_DIR,
            ["test_import_course"],
            static_content_store=content_store,
            do_import_static=False,
            verbose=True,
        )

        return content_store, draft_store
Ejemplo n.º 18
0
    def test_delete(self):
        direct_store = modulestore('direct')
        import_from_xml(direct_store, 'common/test/data/', ['full'])

        sequential = direct_store.get_item(Location(['i4x', 'edX', 'full', 'sequential', 'Administrivia_and_Circuit_Elements', None]))

        chapter = direct_store.get_item(Location(['i4x', 'edX', 'full', 'chapter', 'Week_1', None]))

        # make sure the parent points to the child object which is to be deleted
        self.assertTrue(sequential.location.url() in chapter.children)

        self.client.post(
            reverse('delete_item'),
            json.dumps({'id': sequential.location.url(), 'delete_children': 'true', 'delete_all_versions': 'true'}),
            "application/json"
        )

        found = False
        try:
            direct_store.get_item(Location(['i4x', 'edX', 'full', 'sequential', 'Administrivia_and_Circuit_Elements', None]))
            found = True
        except ItemNotFoundError:
            pass

        self.assertFalse(found)

        chapter = direct_store.get_item(Location(['i4x', 'edX', 'full', 'chapter', 'Week_1', None]))

        # make sure the parent no longer points to the child object which was deleted
        self.assertFalse(sequential.location.url() in chapter.children)
Ejemplo n.º 19
0
    def test_toy_textbooks_loads(self):
        module_store = modulestore()
        import_from_xml(module_store, TEST_DATA_DIR, ["toy"])

        course = module_store.get_item(Location(["i4x", "edX", "toy", "course", "2012_Fall", None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 20
0
    def test_get_items(self):
        '''
        This verifies a bug we had where the None setting in get_items() meant 'wildcard'
        Unfortunately, None = published for the revision field, so get_items() would return
        both draft and non-draft copies.
        '''
        store = modulestore('direct')
        draft_store = modulestore('draft')
        import_from_xml(store, 'common/test/data/', ['simple'])

        html_module = draft_store.get_item(
            ['i4x', 'edX', 'simple', 'html', 'test_html', None])

        draft_store.clone_item(html_module.location, html_module.location)

        # now query get_items() to get this location with revision=None, this should just
        # return back a single item (not 2)

        items = store.get_items(
            ['i4x', 'edX', 'simple', 'html', 'test_html', None])
        self.assertEqual(len(items), 1)
        self.assertFalse(getattr(items[0], 'is_draft', False))

        # now refetch from the draft store. Note that even though we pass
        # None in the revision field, the draft store will replace that with 'draft'
        items = draft_store.get_items(
            ['i4x', 'edX', 'simple', 'html', 'test_html', None])
        self.assertEqual(len(items), 1)
        self.assertTrue(getattr(items[0], 'is_draft', False))
Ejemplo n.º 21
0
    def initdb():
        # connect to the db
        doc_store_config = {
            'host': HOST,
            'db': DB,
            'collection': COLLECTION,
        }
        store = MongoModuleStore(
            doc_store_config, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS,
            xblock_mixins=(XModuleMixin,)
        )
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        content_store = MongoContentStore(HOST, DB)
        #
        # Also test draft store imports
        #
        draft_store = DraftModuleStore(doc_store_config, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
        import_from_xml(store, DATA_DIR, TestMongoModuleStore.courses, draft_store=draft_store, static_content_store=content_store)

        # also test a course with no importing of static content
        import_from_xml(
            store,
            DATA_DIR,
            ['test_import_course'],
            static_content_store=content_store,
            do_import_static=False,
            verbose=True
        )

        return store, content_store, draft_store
Ejemplo n.º 22
0
    def test_update_modulestore_signal_did_fire(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        try:
            module_store.modulestore_update_signal = Signal(
                providing_args=['modulestore', 'course_id', 'location'])

            self.got_signal = False

            def _signal_hander(modulestore=None, course_id=None, location=None, **kwargs):
                self.got_signal = True

            module_store.modulestore_update_signal.connect(_signal_hander)

            new_component_location = Location(
                'i4x', 'edX', 'full', 'html', 'new_component')
            source_template_location = Location(
                'i4x', 'edx', 'templates', 'html', 'Blank_HTML_Page')

            # crate a new module
            module_store.clone_item(
                source_template_location, new_component_location)

        finally:
            module_store.modulestore_update_signal = None

        self.assertTrue(self.got_signal)
Ejemplo n.º 23
0
    def setUp(self):
        super(TestMongoCoursesLoad, self).setUp()
        self.setup_user()

        # Import the toy course into a Mongo-backed modulestore
        self.store = modulestore()
        import_from_xml(self.store, TEST_DATA_DIR, ['toy'])
Ejemplo n.º 24
0
    def test_get_items(self):
        '''
        This verifies a bug we had where the None setting in get_items() meant 'wildcard'
        Unfortunately, None = published for the revision field, so get_items() would return
        both draft and non-draft copies.
        '''
        store = modulestore('direct')
        draft_store = modulestore('draft')
        import_from_xml(store, 'common/test/data/', ['simple'])

        html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])

        draft_store.clone_item(html_module.location, html_module.location)

        # now query get_items() to get this location with revision=None, this should just
        # return back a single item (not 2)

        items = store.get_items(['i4x', 'edX', 'simple', 'html', 'test_html', None])
        self.assertEqual(len(items), 1)
        self.assertFalse(getattr(items[0], 'is_draft', False))

        # now refetch from the draft store. Note that even though we pass
        # None in the revision field, the draft store will replace that with 'draft'
        items = draft_store.get_items(['i4x', 'edX', 'simple', 'html', 'test_html', None])
        self.assertEqual(len(items), 1)
        self.assertTrue(getattr(items[0], 'is_draft', False))
Ejemplo n.º 25
0
    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(modulestore(), self.user.id, 'common/test/data/', ['toy'],
                static_content_store=self.contentstore, verbose=True)

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()

        self.contentstore.set_attr(self.locked_asset, 'locked', True)
    def test_round_trip(self, source_builder, dest_builder, source_content_builder, dest_content_builder, course_data_name):

        # Construct the contentstore for storing the first import
        with source_content_builder.build() as source_content:
            # Construct the modulestore for storing the first import (using the previously created contentstore)
            with source_builder.build(source_content) as source_store:
                # Construct the contentstore for storing the second import
                with dest_content_builder.build() as dest_content:
                    # Construct the modulestore for storing the second import (using the second contentstore)
                    with dest_builder.build(dest_content) as dest_store:
                        source_course_key = source_store.make_course_key('source', 'course', 'key')
                        dest_course_key = dest_store.make_course_key('dest', 'course', 'key')

                        import_from_xml(
                            source_store,
                            'test_user',
                            'common/test/data',
                            course_dirs=[course_data_name],
                            static_content_store=source_content,
                            target_course_id=source_course_key,
                            create_new_course_if_not_present=True,
                        )

                        export_to_xml(
                            source_store,
                            source_content,
                            source_course_key,
                            self.export_dir,
                            'exported_course',
                        )

                        import_from_xml(
                            dest_store,
                            'test_user',
                            self.export_dir,
                            static_content_store=dest_content,
                            target_course_id=dest_course_key,
                            create_new_course_if_not_present=True,
                        )

                        self.exclude_field(None, 'wiki_slug')
                        self.exclude_field(None, 'xml_attributes')
                        self.ignore_asset_key('_id')
                        self.ignore_asset_key('uploadDate')
                        self.ignore_asset_key('content_son')
                        self.ignore_asset_key('thumbnail_location')

                        self.assertCoursesEqual(
                            source_store,
                            source_course_key,
                            dest_store,
                            dest_course_key,
                        )

                        self.assertAssetsEqual(
                            source_content,
                            source_course_key,
                            dest_content,
                            dest_course_key,
                        )
Ejemplo n.º 27
0
    def test_toy_textbooks_loads(self):
        module_store = modulestore()
        import_from_xml(module_store, TEST_DATA_DIR, ['toy'])

        course = module_store.get_item(Location(['i4x', 'edX', 'toy', 'course', '2012_Fall', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 28
0
    def test_full_textbooks_loads(self):
        module_store = modulestore()
        import_from_xml(module_store, TEST_DATA_DIR, ['full'])

        course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 29
0
 def setUp(self):
     CourseTestCase.setUp(self)
     # add in the full class too
     import_from_xml(get_modulestore(
         self.course_location), 'common/test/data/', ['full'])
     self.fullcourse_location = Location(
         ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None])
Ejemplo n.º 30
0
 def initdb():
     # connect to the db
     store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
     # Explicitly list the courses to load (don't want the big one)
     courses = ['toy', 'simple']
     import_from_xml(store, DATA_DIR, courses)
     return store
    def test_generate_find_timings(self, source_ms, num_assets):
        """
        Generate timings for different amounts of asset metadata and different modulestores.
        """
        if CodeBlockTimer is None:
            raise SkipTest("CodeBlockTimer undefined.")

        desc = "FindAssetTest:{}:{}".format(
            SHORT_NAME_MAP[source_ms],
            num_assets,
        )

        with CodeBlockTimer(desc):

            with CodeBlockTimer("fake_assets"):
                # First, make the fake asset metadata.
                make_asset_xml(num_assets, ASSET_XML_PATH)
                validate_xml(ASSET_XSD_PATH, ASSET_XML_PATH)

            # Construct the contentstore for storing the first import
            with MongoContentstoreBuilder().build() as source_content:
                # Construct the modulestore for storing the first import (using the previously created contentstore)
                with source_ms.build(source_content) as source_store:
                    source_course_key = source_store.make_course_key('a', 'course', 'course')
                    asset_key = source_course_key.make_asset_key(
                        AssetMetadata.GENERAL_ASSET_TYPE, 'silly_cat_picture.gif'
                    )

                    with CodeBlockTimer("initial_import"):
                        import_from_xml(
                            source_store,
                            'test_user',
                            TEST_DATA_ROOT,
                            course_dirs=TEST_COURSE,
                            static_content_store=source_content,
                            target_course_id=source_course_key,
                            create_course_if_not_present=True,
                            raise_on_failure=True,
                        )

                    with CodeBlockTimer("find_nonexistent_asset"):
                        # More correct would be using the AssetManager.find() - but since the test
                        # has created its own test modulestore, the AssetManager can't be used.
                        __ = source_store.find_asset_metadata(asset_key)

                    # Perform get_all_asset_metadata for each sort.
                    for sort in ALL_SORTS:
                        with CodeBlockTimer("get_asset_list:{}-{}".format(
                            sort[0],
                            'asc' if sort[1] == ModuleStoreEnum.SortOrder.ascending else 'desc'
                        )):
                            # Grab two ranges of 50 assets using different sorts.
                            # Why 50? That's how many are displayed on the current Studio "Files & Uploads" page.
                            start_middle = num_assets / 2
                            __ = source_store.get_all_asset_metadata(
                                source_course_key, 'asset', start=0, sort=sort, maxresults=50
                            )
                            __ = source_store.get_all_asset_metadata(
                                source_course_key, 'asset', start=start_middle, sort=sort, maxresults=50
                            )
Ejemplo n.º 32
0
 def test_rewrite_reference_list(self):
     # This test fails with split modulestore (the HTML component is not in "different_course_id" namespace).
     # More investigation needs to be done.
     module_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
     target_course_id = module_store.make_course_key('testX', 'conditional_copy', 'copy_run')
     import_from_xml(
         module_store,
         self.user.id,
         TEST_DATA_DIR,
         ['conditional'],
         target_course_id=target_course_id
     )
     conditional_module = module_store.get_item(
         target_course_id.make_usage_key('conditional', 'condone')
     )
     self.assertIsNotNone(conditional_module)
     different_course_id = module_store.make_course_key('edX', 'different_course', None)
     self.assertListEqual(
         [
             target_course_id.make_usage_key('problem', 'choiceprob'),
             different_course_id.make_usage_key('html', 'for_testing_import_rewrites')
         ],
         conditional_module.sources_list
     )
     self.assertListEqual(
         [
             target_course_id.make_usage_key('html', 'congrats'),
             target_course_id.make_usage_key('html', 'secret_page')
         ],
         conditional_module.show_tag_list
     )
Ejemplo n.º 33
0
    def test_clone_course(self):

        course_data = {
            'template': 'i4x://edx/templates/course/Empty',
            'org': 'MITx',
            'number': '999',
            'display_name': 'Robot Super Course',
        }

        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        resp = self.client.post(reverse('create_new_course'), course_data)
        self.assertEqual(resp.status_code, 200)
        data = parse_json(resp)
        self.assertEqual(data['id'], 'i4x://MITx/999/course/Robot_Super_Course')

        content_store = contentstore()

        source_location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')
        dest_location = CourseDescriptor.id_to_location('MITx/999/Robot_Super_Course')

        clone_course(module_store, content_store, source_location, dest_location)

        # now loop through all the units in the course and verify that the clone can render them, which
        # means the objects are at least present
        items = module_store.get_items(Location(['i4x', 'edX', 'full', 'vertical', None]))
        self.assertGreater(len(items), 0)
        clone_items = module_store.get_items(Location(['i4x', 'MITx', '999', 'vertical', None]))
        self.assertGreater(len(clone_items), 0)
        for descriptor in items:
            new_loc = descriptor.location.replace(org='MITx', course='999')
            print "Checking {0} should now also be at {1}".format(descriptor.location.url(), new_loc.url())
            resp = self.client.get(reverse('edit_unit', kwargs={'location': new_loc.url()}))
            self.assertEqual(resp.status_code, 200)
Ejemplo n.º 34
0
    def test_import_textbook_as_content_element(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 35
0
    def test_clone_course(self):

        course_data = {
            "template": "i4x://edx/templates/course/Empty",
            "org": "MITx",
            "number": "999",
            "display_name": "Robot Super Course",
        }

        module_store = modulestore("direct")
        import_from_xml(module_store, "common/test/data/", ["full"])

        resp = self.client.post(reverse("create_new_course"), course_data)
        self.assertEqual(resp.status_code, 200)
        data = parse_json(resp)
        self.assertEqual(data["id"], "i4x://MITx/999/course/Robot_Super_Course")

        content_store = contentstore()

        source_location = CourseDescriptor.id_to_location("edX/full/6.002_Spring_2012")
        dest_location = CourseDescriptor.id_to_location("MITx/999/Robot_Super_Course")

        clone_course(module_store, content_store, source_location, dest_location)

        # now loop through all the units in the course and verify that the clone can render them, which
        # means the objects are at least present
        items = module_store.get_items(Location(["i4x", "edX", "full", "vertical", None]))
        self.assertGreater(len(items), 0)
        clone_items = module_store.get_items(Location(["i4x", "MITx", "999", "vertical", None]))
        self.assertGreater(len(clone_items), 0)
        for descriptor in items:
            new_loc = descriptor.location.replace(org="MITx", course="999")
            print "Checking {0} should now also be at {1}".format(descriptor.location.url(), new_loc.url())
            resp = self.client.get(reverse("edit_unit", kwargs={"location": new_loc.url()}))
            self.assertEqual(resp.status_code, 200)
Ejemplo n.º 36
0
 def test_rewrite_reference_list(self):
     module_store = modulestore('direct')
     target_location = Location(['i4x', 'testX', 'conditional_copy', 'course', 'copy_run'])
     import_from_xml(
         module_store,
         'common/test/data/',
         ['conditional'],
         target_location_namespace=target_location
     )
     conditional_module = module_store.get_item(
         Location(['i4x', 'testX', 'conditional_copy', 'conditional', 'condone'])
     )
     self.assertIsNotNone(conditional_module)
     self.assertListEqual(
         [
             u'i4x://testX/conditional_copy/problem/choiceprob',
             u'i4x://edX/different_course/html/for_testing_import_rewrites'
         ],
         conditional_module.sources_list
     )
     self.assertListEqual(
         [
             u'i4x://testX/conditional_copy/html/congrats',
             u'i4x://testX/conditional_copy/html/secret_page'
         ],
         conditional_module.show_tag_list
     )
Ejemplo n.º 37
0
    def test_delete(self):
        direct_store = modulestore("direct")
        import_from_xml(direct_store, "common/test/data/", ["full"])

        sequential = direct_store.get_item(
            Location(["i4x", "edX", "full", "sequential", "Administrivia_and_Circuit_Elements", None])
        )

        chapter = direct_store.get_item(Location(["i4x", "edX", "full", "chapter", "Week_1", None]))

        # make sure the parent points to the child object which is to be deleted
        self.assertTrue(sequential.location.url() in chapter.children)

        self.client.post(
            reverse("delete_item"),
            json.dumps({"id": sequential.location.url(), "delete_children": "true", "delete_all_versions": "true"}),
            "application/json",
        )

        found = False
        try:
            direct_store.get_item(
                Location(["i4x", "edX", "full", "sequential", "Administrivia_and_Circuit_Elements", None])
            )
            found = True
        except ItemNotFoundError:
            pass

        self.assertFalse(found)

        chapter = direct_store.get_item(Location(["i4x", "edX", "full", "chapter", "Week_1", None]))

        # make sure the parent no longer points to the child object which was deleted
        self.assertFalse(sequential.location.url() in chapter.children)
Ejemplo n.º 38
0
    def test_remove_hide_progress_tab(self):
        module_store = modulestore("direct")
        import_from_xml(module_store, "common/test/data/", ["full"])

        source_location = CourseDescriptor.id_to_location("edX/full/6.002_Spring_2012")
        course = module_store.get_item(source_location)
        self.assertFalse(course.hide_progress_tab)
Ejemplo n.º 39
0
    def test_get_depth_with_drafts(self):
        import_from_xml(modulestore("direct"), "common/test/data/", ["simple"])

        course = modulestore("draft").get_item(
            Location(["i4x", "edX", "simple", "course", "2012_Fall", None]), depth=None
        )

        # make sure no draft items have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 0)

        problem = modulestore("draft").get_item(Location(["i4x", "edX", "simple", "problem", "ps01-simple", None]))

        # put into draft
        modulestore("draft").clone_item(problem.location, problem.location)

        # make sure we can query that item and verify that it is a draft
        draft_problem = modulestore("draft").get_item(
            Location(["i4x", "edX", "simple", "problem", "ps01-simple", None])
        )
        self.assertTrue(getattr(draft_problem, "is_draft", False))

        # now requery with depth
        course = modulestore("draft").get_item(
            Location(["i4x", "edX", "simple", "course", "2012_Fall", None]), depth=None
        )

        # make sure just one draft item have been returned
        num_drafts = self._get_draft_counts(course)
        self.assertEqual(num_drafts, 1)
Ejemplo n.º 40
0
    def test_import_textbook_as_content_element(self):
        module_store = modulestore("direct")
        import_from_xml(module_store, "common/test/data/", ["full"])

        course = module_store.get_item(Location(["i4x", "edX", "full", "course", "6.002_Spring_2012", None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 41
0
    def test_locking(self):
        """
        Tests a simple locking and unlocking of an asset in the toy course.
        """
        def verify_asset_locked_state(locked):
            """ Helper method to verify lock state in the contentstore """
            asset_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/sample_static.txt')
            content = contentstore().find(asset_location)
            self.assertEqual(content.locked, locked)

        def post_asset_update(lock):
            """ Helper method for posting asset update. """
            upload_date = datetime(2013, 6, 1, 10, 30, tzinfo=UTC)
            location = Location(['c4x', 'edX', 'toy', 'asset', 'sample_static.txt'])
            url = reverse('update_asset', kwargs={'org': 'edX', 'course': 'toy', 'name': '2012_Fall'})

            resp = self.client.post(url, json.dumps(assets._get_asset_json("sample_static.txt", upload_date, location, None, lock)), "application/json")
            self.assertEqual(resp.status_code, 201)
            return json.loads(resp.content)

        # Load the toy course.
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['toy'], static_content_store=contentstore(), verbose=True)
        verify_asset_locked_state(False)

        # Lock the asset
        resp_asset = post_asset_update(True)
        self.assertTrue(resp_asset['locked'])
        verify_asset_locked_state(True)

        # Unlock the asset
        resp_asset = post_asset_update(False)
        self.assertFalse(resp_asset['locked'])
        verify_asset_locked_state(False)
Ejemplo n.º 42
0
 def test_rewrite_reference_list(self):
     module_store = modulestore()
     target_course_id = SlashSeparatedCourseKey('testX', 'conditional_copy', 'copy_run')
     import_from_xml(
         module_store,
         self.user.id,
         'common/test/data/',
         ['conditional'],
         target_course_id=target_course_id
     )
     conditional_module = module_store.get_item(
         target_course_id.make_usage_key('conditional', 'condone')
     )
     self.assertIsNotNone(conditional_module)
     different_course_id = SlashSeparatedCourseKey('edX', 'different_course', None)
     self.assertListEqual(
         [
             target_course_id.make_usage_key('problem', 'choiceprob'),
             different_course_id.make_usage_key('html', 'for_testing_import_rewrites')
         ],
         conditional_module.sources_list
     )
     self.assertListEqual(
         [
             target_course_id.make_usage_key('html', 'congrats'),
             target_course_id.make_usage_key('html', 'secret_page')
         ],
         conditional_module.show_tag_list
     )
Ejemplo n.º 43
0
 def setUp(self):
     CourseTestCase.setUp(self)
     # add in the full class too
     import_from_xml(get_modulestore(self.course_location),
                     'common/test/data/', ['full'])
     self.fullcourse_location = Location(
         ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None])
Ejemplo n.º 44
0
    def test_remove_hide_progress_tab(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        source_location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')
        course = module_store.get_item(source_location)
        self.assertFalse(course.hide_progress_tab)
Ejemplo n.º 45
0
    def test_remove_hide_progress_tab(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        source_location = CourseDescriptor.id_to_location(
            'edX/full/6.002_Spring_2012')
        course = module_store.get_item(source_location)
        self.assertFalse(course.hide_progress_tab)
Ejemplo n.º 46
0
 def initdb():
     # connect to the db
     store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
     # Explicitly list the courses to load (don't want the big one)
     courses = ['toy', 'simple']
     import_from_xml(store, DATA_DIR, courses)
     update_templates(store)
     return store
Ejemplo n.º 47
0
    def check_edit_unit(self, test_course_name):
        import_from_xml(modulestore('direct'), 'common/test/data/', [test_course_name])

        for descriptor in modulestore().get_items(Location(None, None, 'vertical', None, None)):
            print "Checking ", descriptor.location.url()
            print descriptor.__class__, descriptor.location
            resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()}))
            self.assertEqual(resp.status_code, 200)
Ejemplo n.º 48
0
    def test_generate_import_export_timings(self, source_ms, dest_ms,
                                            num_assets):
        """
        Generate timings for different amounts of asset metadata and different modulestores.
        """
        if CodeBlockTimer is None:
            raise SkipTest("CodeBlockTimer undefined.")

        desc = "XMLRoundTrip:{}->{}:{}".format(SHORT_NAME_MAP[source_ms],
                                               SHORT_NAME_MAP[dest_ms],
                                               num_assets)

        with CodeBlockTimer(desc):

            with CodeBlockTimer("fake_assets"):
                # First, make the fake asset metadata.
                make_asset_xml(num_assets, ASSET_XML_PATH)
                validate_xml(ASSET_XSD_PATH, ASSET_XML_PATH)

            with source_ms.build() as (source_content, source_store):
                with dest_ms.build() as (dest_content, dest_store):
                    source_course_key = source_store.make_course_key(
                        'a', 'course', 'course')
                    dest_course_key = dest_store.make_course_key(
                        'a', 'course', 'course')

                    with CodeBlockTimer("initial_import"):
                        import_from_xml(
                            source_store,
                            'test_user',
                            TEST_DATA_ROOT,
                            course_dirs=TEST_COURSE,
                            static_content_store=source_content,
                            target_course_id=source_course_key,
                            create_course_if_not_present=True,
                            raise_on_failure=True,
                        )

                    with CodeBlockTimer("export"):
                        export_to_xml(
                            source_store,
                            source_content,
                            source_course_key,
                            self.export_dir,
                            'exported_source_course',
                        )

                    with CodeBlockTimer("second_import"):
                        import_from_xml(
                            dest_store,
                            'test_user',
                            self.export_dir,
                            course_dirs=['exported_source_course'],
                            static_content_store=dest_content,
                            target_course_id=dest_course_key,
                            create_course_if_not_present=True,
                            raise_on_failure=True,
                        )
Ejemplo n.º 49
0
    def test_import_textbook_as_content_element(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        course = module_store.get_item(
            Location(
                ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 50
0
    def load_courses(self):
        """Load test courses and return list of ids"""
        store = modulestore()

        courses = store.get_courses()
        if TEST_COURSE_ID not in [c.id for c in courses]:
            import_from_xml(store, DATA_DIR, ['toy', 'simple'])

        return [course.id for course in store.get_courses()]
Ejemplo n.º 51
0
    def test_no_static_link_rewrites_on_import(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['toy'], do_import_static=False, verbose=True)

        handouts = module_store.get_item(Location(['i4x', 'edX', 'toy', 'course_info', 'handouts', None]))
        self.assertIn('/static/', handouts.data)

        handouts = module_store.get_item(Location(['i4x', 'edX', 'toy', 'html', 'toyhtml', None]))
        self.assertIn('/static/', handouts.data)
Ejemplo n.º 52
0
    def test_full_textbooks_loads(self):
        module_store = modulestore()
        import_from_xml(module_store, TEST_DATA_DIR, ['full'])

        course = module_store.get_item(
            Location(
                ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        self.assertGreater(len(course.textbooks), 0)
Ejemplo n.º 53
0
    def test_asset_sizes(self, source_ms, num_assets):
        """
        Generate timings for different amounts of asset metadata and different modulestores.
        """
        # First, make the fake asset metadata.
        make_asset_xml(num_assets, ASSET_XML_PATH)
        validate_xml(ASSET_XSD_PATH, ASSET_XML_PATH)

        # Construct the contentstore for storing the first import
        with MongoContentstoreBuilder().build() as source_content:
            # Construct the modulestore for storing the first import (using the previously created contentstore)
            with source_ms.build(source_content) as source_store:
                source_course_key = source_store.make_course_key(
                    'a', 'course', 'course')

                import_from_xml(
                    source_store,
                    'test_user',
                    TEST_DATA_ROOT,
                    course_dirs=TEST_COURSE,
                    static_content_store=source_content,
                    target_course_id=source_course_key,
                    create_course_if_not_present=True,
                    raise_on_failure=True,
                )

                asset_collection = source_ms.asset_collection()
                # Ensure the asset collection exists.
                if asset_collection.name in asset_collection.database.collection_names(
                ):

                    # Map gets the size of each structure.
                    mapper = Code("""
                        function() { emit("size", (this == null) ? 0 : Object.bsonsize(this)) }
                        """)

                    # Reduce finds the largest structure size and returns only it.
                    reducer = Code("""
                        function(key, values) {
                            var max_size = 0;
                            for (var i=0; i < values.length; i++) {
                                if (values[i] > max_size) {
                                    max_size = values[i];
                                }
                            }
                            return max_size;
                        }
                    """)

                    results = asset_collection.map_reduce(
                        mapper, reducer, "size_results")
                    result_str = "{} - Store: {:<15} - Num Assets: {:>6} - Result: {}\n".format(
                        self.test_run_time, SHORT_NAME_MAP[source_ms],
                        num_assets, [r for r in results.find()])
                    with open("bson_sizes.txt", "a") as f:
                        f.write(result_str)
Ejemplo n.º 54
0
    def test_malformed_edit_unit_request(self):
        store = modulestore('direct')
        import_from_xml(store, 'common/test/data/', ['simple'])

        # just pick one vertical
        descriptor = store.get_items(Location('i4x', 'edX', 'simple', 'vertical', None, None))[0]
        location = descriptor.location._replace(name='.' + descriptor.location.name)

        resp = self.client.get(reverse('edit_unit', kwargs={'location': location.url()}))
        self.assertEqual(resp.status_code, 400)
Ejemplo n.º 55
0
    def test_import_polls(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        items = module_store.get_items(['i4x', 'edX', 'full', 'poll_question', None, None])
        found = len(items) > 0

        self.assertTrue(found)
        # check that there's actually content in the 'question' field
        self.assertGreater(len(items[0].question), 0)
Ejemplo n.º 56
0
    def test_delete_course(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        content_store = contentstore()

        location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')

        delete_course(module_store, content_store, location, commit=True)

        items = module_store.get_items(Location(['i4x', 'edX', 'full', 'vertical', None]))
        self.assertEqual(len(items), 0)
Ejemplo n.º 57
0
    def load_test_import_course(self):
        '''
        Load the standard course used to test imports (for do_import_static=False behavior).
        '''
        content_store = contentstore()
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['test_import_course'], static_content_store=content_store, do_import_static=False, verbose=True)
        course_location = CourseDescriptor.id_to_location('edX/test_import_course/2012_Fall')
        course = module_store.get_item(course_location)
        self.assertIsNotNone(course)

        return module_store, content_store, course, course_location
Ejemplo n.º 58
0
    def import_and_populate_course(self):
        """
        Imports the test toy course and populates it with additional test data
        """
        content_store = contentstore()
        import_from_xml(self.store, self.user.id, 'common/test/data/', ['toy'], static_content_store=content_store)
        course_id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        # create an Orphan
        # We had a bug where orphaned draft nodes caused export to fail. This is here to cover that case.
        vertical = self.store.get_item(course_id.make_usage_key('vertical', self.TEST_VERTICAL), depth=1)
        vertical.location = vertical.location.replace(name='no_references')
        self.store.update_item(vertical, self.user.id, allow_not_found=True)
        orphan_vertical = self.store.get_item(vertical.location)
        self.assertEqual(orphan_vertical.location.name, 'no_references')
        self.assertEqual(len(orphan_vertical.children), len(vertical.children))

        # create a Draft vertical
        vertical = self.store.get_item(course_id.make_usage_key('vertical', self.TEST_VERTICAL), depth=1)
        draft_vertical = self.store.convert_to_draft(vertical.location, self.user.id)
        self.assertTrue(self.store.has_published_version(draft_vertical))

        # create a Private (draft only) vertical
        private_vertical = self.store.create_item(self.user.id, course_id, 'vertical', self.PRIVATE_VERTICAL)
        self.assertFalse(self.store.has_published_version(private_vertical))

        # create a Published (no draft) vertical
        public_vertical = self.store.create_item(self.user.id, course_id, 'vertical', self.PUBLISHED_VERTICAL)
        public_vertical = self.store.publish(public_vertical.location, self.user.id)
        self.assertTrue(self.store.has_published_version(public_vertical))

        # add the new private and new public as children of the sequential
        sequential = self.store.get_item(course_id.make_usage_key('sequential', self.SEQUENTIAL))
        sequential.children.append(private_vertical.location)
        sequential.children.append(public_vertical.location)
        self.store.update_item(sequential, self.user.id)

        # lock an asset
        content_store.set_attr(self.LOCKED_ASSET_KEY, 'locked', True)

        # create a non-portable link - should be rewritten in new courses
        html_module = self.store.get_item(course_id.make_usage_key('html', 'nonportable'))
        new_data = html_module.data = html_module.data.replace(
            '/static/',
            '/c4x/{0}/{1}/asset/'.format(course_id.org, course_id.course)
        )
        self.store.update_item(html_module, self.user.id)

        html_module = self.store.get_item(html_module.location)
        self.assertEqual(new_data, html_module.data)

        return course_id
Ejemplo n.º 59
0
    def test_metadata_inheritance(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        course = module_store.get_item(
            Location(
                ['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        verticals = module_store.get_items(
            ['i4x', 'edX', 'full', 'vertical', None, None])

        # let's assert on the metadata_inheritance on an existing vertical
        for vertical in verticals:
            self.assertEqual(course.lms.xqa_key, vertical.lms.xqa_key)

        self.assertGreater(len(verticals), 0)

        new_component_location = Location('i4x', 'edX', 'full', 'html',
                                          'new_component')
        source_template_location = Location('i4x', 'edx', 'templates', 'html',
                                            'Blank_HTML_Page')

        # crate a new module and add it as a child to a vertical
        module_store.clone_item(source_template_location,
                                new_component_location)
        parent = verticals[0]
        module_store.update_children(
            parent.location, parent.children + [new_component_location.url()])

        # flush the cache
        module_store.refresh_cached_metadata_inheritance_tree(
            new_component_location)
        new_module = module_store.get_item(new_component_location)

        # check for grace period definition which should be defined at the course level
        self.assertEqual(parent.lms.graceperiod, new_module.lms.graceperiod)

        self.assertEqual(course.lms.xqa_key, new_module.lms.xqa_key)

        #
        # now let's define an override at the leaf node level
        #
        new_module.lms.graceperiod = timedelta(1)
        module_store.update_metadata(new_module.location,
                                     own_metadata(new_module))

        # flush the cache and refetch
        module_store.refresh_cached_metadata_inheritance_tree(
            new_component_location)
        new_module = module_store.get_item(new_component_location)

        self.assertEqual(timedelta(1), new_module.lms.graceperiod)
Ejemplo n.º 60
0
    def test_export_all_courses(self):
        """
        This test validates that redundant Mac metadata files ('._example.txt', '.DS_Store') are
        cleaned up on import
        """
        import_from_xml(self.module_store,
                        '**replace_user**',
                        'common/test/data/', ['dot-underscore'],
                        static_content_store=self.content_store,
                        do_import_static=True,
                        verbose=True)

        course = self.module_store.get_course(
            SlashSeparatedCourseKey('edX', 'dot-underscore', '2014_Fall'))
        self.assertIsNotNone(course)

        # check that there are two assets ['example.txt', '.example.txt'] in contentstore for imported course
        all_assets, count = self.content_store.get_all_content_for_course(
            course.id)
        self.assertEqual(count, 2)
        self.assertEqual(set([asset['_id']['name'] for asset in all_assets]),
                         set([u'.example.txt', u'example.txt']))

        # manually add redundant assets (file ".DS_Store" and filename starts with "._")
        course_filter = course.id.make_asset_key("asset", None)
        query = location_to_query(course_filter,
                                  wildcard=True,
                                  tag=XASSET_LOCATION_TAG)
        query['_id.name'] = all_assets[0]['_id']['name']
        asset_doc = self.content_store.fs_files.find_one(query)
        asset_doc['_id']['name'] = u'._example_test.txt'
        self.content_store.fs_files.insert(asset_doc)
        asset_doc['_id']['name'] = u'.DS_Store'
        self.content_store.fs_files.insert(asset_doc)

        # check that now course has four assets
        all_assets, count = self.content_store.get_all_content_for_course(
            course.id)
        self.assertEqual(count, 4)
        self.assertEqual(
            set([asset['_id']['name'] for asset in all_assets]),
            set([
                u'.example.txt', u'example.txt', u'._example_test.txt',
                u'.DS_Store'
            ]))
        # now call asset_cleanup command and check that there is only two proper assets in contentstore for the course
        call_command('cleanup_assets')
        all_assets, count = self.content_store.get_all_content_for_course(
            course.id)
        self.assertEqual(count, 2)
        self.assertEqual(set([asset['_id']['name'] for asset in all_assets]),
                         set([u'.example.txt', u'example.txt']))