Esempio n. 1
0
    def test_libraries_on_index(self):
        """
        Test that the library tab is present.
        """
        def _assert_library_tab_present(response):
            """
            Asserts there's a library tab.
            """
            parsed_html = lxml.html.fromstring(response.content)
            library_tab = parsed_html.find_class('react-library-listing')
            self.assertEqual(len(library_tab), 1)

        # Add a library:
        lib1 = LibraryFactory.create()

        index_url = '/home/'
        index_response = self.client.get(index_url, {}, HTTP_ACCEPT='text/html')
        _assert_library_tab_present(index_response)

        # Make sure libraries are visible to non-staff users too
        self.client.logout()
        non_staff_user, non_staff_userpassword = self.create_non_staff_user()
        lib2 = LibraryFactory.create(user_id=non_staff_user.id)
        LibraryUserRole(lib2.location.library_key).add_users(non_staff_user)
        self.client.login(username=non_staff_user.username, password=non_staff_userpassword)
        index_response = self.client.get(index_url, {}, HTTP_ACCEPT='text/html')
        _assert_library_tab_present(index_response)
    def test_libraries_on_course_index(self):
        """
        Test getting the list of libraries from the course listing page
        """
        def _assert_library_link_present(response, library):
            """
            Asserts there's a valid library link on libraries tab.
            """
            parsed_html = lxml.html.fromstring(response.content)
            library_link_elements = parsed_html.find_class('library-link')
            self.assertEqual(len(library_link_elements), 1)
            link = library_link_elements[0]
            self.assertEqual(
                link.get("href"),
                reverse_library_url('library_handler', library.location.library_key),
            )
            # now test that url
            outline_response = self.client.get(link.get("href"), {}, HTTP_ACCEPT='text/html')
            self.assertEqual(outline_response.status_code, 200)

        # Add a library:
        lib1 = LibraryFactory.create()

        index_url = '/home/'
        index_response = self.client.get(index_url, {}, HTTP_ACCEPT='text/html')
        _assert_library_link_present(index_response, lib1)

        # Make sure libraries are visible to non-staff users too
        self.client.logout()
        non_staff_user, non_staff_userpassword = self.create_non_staff_user()
        lib2 = LibraryFactory.create(user_id=non_staff_user.id)
        LibraryUserRole(lib2.location.library_key).add_users(non_staff_user)
        self.client.login(username=non_staff_user.username, password=non_staff_userpassword)
        index_response = self.client.get(index_url, {}, HTTP_ACCEPT='text/html')
        _assert_library_link_present(index_response, lib2)
Esempio n. 3
0
 def test_duplicate_library(self):
     """
     Make sure we cannot create duplicate libraries
     """
     org, lib_code = ("DuplicateX", "DUP")
     LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
     with self.assertRaises(DuplicateCourseError):
         LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
Esempio n. 4
0
    def test_create_library(self):
        """
        Test that we can create a library, and see how many mongo calls it uses to do so.

        Expected mongo calls, in order:
        find_one({'org': '...', 'run': 'library', 'course': '...'})
        insert(definition: {'block_type': 'library', 'fields': {}})

        insert_structure(bulk)
        insert_course_index(bulk)
        get_course_index(bulk)
        """
        with check_mongo_calls(2, 3):
            LibraryFactory.create(modulestore=self.store)
Esempio n. 5
0
    def test_manage_library_users(self):
        """
        Simple test that the Library "User Access" view works.
        Also tests that we can use the REST API to assign a user to a library.
        """
        library = LibraryFactory.create()
        extra_user, _ = self.create_non_staff_user()
        manage_users_url = reverse_library_url('manage_library_users', unicode(library.location.library_key))

        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        # extra_user has not been assigned to the library so should not show up in the list:
        self.assertNotIn(extra_user.username, response.content)

        # Now add extra_user to the library:
        user_details_url = reverse_course_url(
            'course_team_handler',
            library.location.library_key, kwargs={'email': extra_user.email}
        )
        edit_response = self.client.ajax_post(user_details_url, {"role": LibraryUserRole.ROLE})
        self.assertIn(edit_response.status_code, (200, 204))

        # Now extra_user should apear in the list:
        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        self.assertIn(extra_user.username, response.content)
    def test_library_author_view_with_paging(self):
        """
        Test that LibraryRoot.author_view can apply paging
        We have to patch the runtime (module system) in order to be able to
        render blocks in our test environment.
        """
        library = LibraryFactory.create(modulestore=self.store)
        # Add five HTML blocks to the library:
        blocks = [
            ItemFactory.create(
                category="html",
                parent_location=library.location,
                user_id=self.user_id,
                publish_item=False,
                modulestore=self.store,
                data="HtmlBlock" + str(i)
            )
            for i in range(5)
        ]
        library = self.store.get_library(library.location.library_key)

        def render_and_check_contents(page, page_size):
            """ Renders block and asserts on returned content """
            context = {'reorderable_items': set(), 'paging': {'page_number': page, 'page_size': page_size}}
            expected_blocks = blocks[page_size * page:page_size * (page + 1)]
            result = library.render(AUTHOR_VIEW, context)

            for expected_block in expected_blocks:
                self.assertIn(expected_block.data, result.content)

        render_and_check_contents(0, 3)
        render_and_check_contents(1, 3)
        render_and_check_contents(0, 2)
        render_and_check_contents(1, 2)
    def test_library_author_view(self):
        """
        Test that LibraryRoot.author_view can run and includes content from its
        children.
        We have to patch the runtime (module system) in order to be able to
        render blocks in our test environment.
        """
        message = u"Hello world"
        library = LibraryFactory.create(modulestore=self.store)
        # Add one HTML block to the library:
        ItemFactory.create(
            category="html",
            parent_location=library.location,
            user_id=self.user_id,
            publish_item=False,
            modulestore=self.store,
            data=message
        )
        library = self.store.get_library(library.location.library_key)

        context = {'reorderable_items': set(), }
        # Patch the HTML block to always render "Hello world"

        result = library.render(AUTHOR_VIEW, context)
        self.assertIn(message, result.content)
    def test_library_import_branch_settings(self, branch_setting):
        """
        Try importing a known good library archive under either branch setting.
        The branch setting should have no effect on library import.
        """
        with self.store.branch_setting(branch_setting):
            library = LibraryFactory.create(modulestore=self.store)
            lib_key = library.location.library_key
            extract_dir = path(tempfile.mkdtemp(dir=settings.DATA_DIR))
            # the extract_dir needs to be passed as a relative dir to
            # import_library_from_xml
            extract_dir_relative = path.relpath(extract_dir, settings.DATA_DIR)

            try:
                with tarfile.open(path(TEST_DATA_DIR) / 'imports' / 'library.HhJfPD.tar.gz') as tar:
                    safetar_extractall(tar, extract_dir)
                import_library_from_xml(
                    self.store,
                    self.user.id,
                    settings.GITHUB_REPO_ROOT,
                    [extract_dir_relative / 'library'],
                    load_error_modules=False,
                    static_content_store=contentstore(),
                    target_id=lib_key
                )
            finally:
                shutil.rmtree(extract_dir)
 def test_library_export(self):
     """
     Verify that useable library data can be exported.
     """
     youtube_id = "qS4NO9MNC6w"
     library = LibraryFactory.create(modulestore=self.store)
     video_block = ItemFactory.create(
         category="video",
         parent_location=library.location,
         user_id=self.user.id,
         publish_item=False,
         youtube_id_1_0=youtube_id
     )
     name = library.url_name
     lib_key = library.location.library_key
     root_dir = path(tempfile.mkdtemp())
     try:
         export_library_to_xml(self.store, contentstore(), lib_key, root_dir, name)
         lib_xml = lxml.etree.XML(open(root_dir / name / LIBRARY_ROOT).read())
         self.assertEqual(lib_xml.get('org'), lib_key.org)
         self.assertEqual(lib_xml.get('library'), lib_key.library)
         block = lib_xml.find('video')
         self.assertIsNotNone(block)
         self.assertEqual(block.get('url_name'), video_block.url_name)
         video_xml = lxml.etree.XML(open(root_dir / name / 'video' / video_block.url_name + '.xml').read())
         self.assertEqual(video_xml.tag, 'video')
         self.assertEqual(video_xml.get('youtube_id_1_0'), youtube_id)
     finally:
         shutil.rmtree(root_dir / name)
    def test_copy_from_template_publish(self):
        """
        Test that copy_from_template's "defaults" data is not lost
        when blocks are published.
        """
        # Create a library with a problem:
        source_library = LibraryFactory.create(modulestore=self.store)
        display_name_expected = "CUSTOM Library Display Name"
        self.make_block("problem", source_library, display_name=display_name_expected)
        # Reload source_library since we need its branch and version to use copy_from_template:
        source_library = self.store.get_library(
            source_library.location.library_key, remove_version=False, remove_branch=False
        )
        # And a course with a vertical:
        course = CourseFactory.create(modulestore=self.store)
        self.make_block("vertical", course)

        problem_key_in_course = self.store.copy_from_template(
            source_library.children, dest_key=course.location, user_id=self.user_id
        )[0]

        # We do the following twice because different methods get used inside
        # split modulestore on first vs. subsequent publish
        for __ in range(2):
            # Publish:
            self.store.publish(problem_key_in_course, self.user_id)
            # Test that the defaults values are there.
            problem_published = self.store.get_item(
                problem_key_in_course.for_branch(ModuleStoreEnum.BranchName.published)
            )
            self.assertEqual(problem_published.display_name, display_name_expected)
Esempio n. 11
0
    def test_library_author_view(self):
        """
        Test that LibraryRoot.author_view can run and includes content from its
        children.
        We have to patch the runtime (module system) in order to be able to
        render blocks in our test environment.
        """
        library = LibraryFactory.create(modulestore=self.store)
        # Add one HTML block to the library:
        ItemFactory.create(
            category="html",
            parent_location=library.location,
            user_id=self.user_id,
            publish_item=False,
            modulestore=self.store,
        )
        library = self.store.get_library(library.location.library_key)

        context = {"reorderable_items": set()}
        # Patch the HTML block to always render "Hello world"
        message = u"Hello world"
        hello_render = lambda _, context: Fragment(message)
        with patch("xmodule.html_module.HtmlDescriptor.author_view", hello_render, create=True):
            with patch("xmodule.x_module.descriptor_global_get_asides", lambda block: []):
                result = library.render(AUTHOR_VIEW, context)
        self.assertIn(message, result.content)
Esempio n. 12
0
    def test_no_access(self):
        user, password = self.create_non_staff_user()
        self.client.login(username=user, password=password)

        lib = LibraryFactory.create()
        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 403)
    def setUp(self):
        """ Setup method - create courses """
        super(TestReindexCourse, self).setUp()
        self.store = modulestore()
        self.first_lib = LibraryFactory.create(
            org="test", library="lib1", display_name="run1", default_store=ModuleStoreEnum.Type.split
        )
        self.second_lib = LibraryFactory.create(
            org="test", library="lib2", display_name="run2", default_store=ModuleStoreEnum.Type.split
        )

        self.first_course = CourseFactory.create(
            org="test", course="course1", display_name="run1"
        )
        self.second_course = CourseFactory.create(
            org="test", course="course2", display_name="run1"
        )
Esempio n. 14
0
 def test_str_repr(self, name):
     """
     Test __unicode__() and __str__() methods of libraries
     """
     library = LibraryFactory.create(metadata={"display_name": name}, modulestore=self.store)
     self.assertIn(name, unicode(library))
     if not isinstance(name, unicode):
         self.assertIn(name, str(library))
Esempio n. 15
0
 def test_bad_http_verb_with_lib_key(self):
     """
     We should get an error if we do weird requests to /library/
     """
     lib = LibraryFactory.create()
     for verb in ("post", "delete", "put"):
         response = getattr(self.client, verb)(make_url_for_lib(lib.location.library_key))
         self.assertEqual(response.status_code, 405)
Esempio n. 16
0
 def test_list_available_libraries(self):
     """
     Test listing of libraries.
     """
     _ = LibraryFactory.create(modulestore=self.store)
     all_libraries = self.tools.list_available_libraries()
     self.assertTrue(all_libraries)
     self.assertEqual(len(all_libraries), 1)
Esempio n. 17
0
    def setUpClass(cls):

        super(LibraryTestCase, cls).setUpClass()

        cls.library = LibraryFactory.create(modulestore=cls.store)
        creator = UserFactory()

        cls.library_blocks = [
            ItemFactory.create(
                category="html",
                parent=cls.library,
                parent_location=cls.library.location,
                publish_item=False,
                user_id=creator.id,
                modulestore=cls.store,
            ) for _ in range(3)
        ]
        cls.libtools = LibraryToolsService(cls.store)
        cls.store.update_item(cls.library, creator.id)

        with cls.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, None):
            cls.course = CourseFactory.create(modulestore=cls.store)
            cls.course_key = cls.course.id

            with cls.store.bulk_operations(cls.course_key, emit_signals=False):
                cls.chapter = ItemFactory.create(
                    parent=cls.course,
                    parent_location=cls.course.location,
                    category="chapter",
                    modulestore=cls.store,
                    publish_item=False,
                )
                cls.sequential = ItemFactory.create(
                    parent=cls.chapter,
                    parent_location=cls.chapter.location,
                    category='sequential',
                    modulestore=cls.store,
                    publish_item=False,
                )
                cls.vertical = ItemFactory.create(
                    parent=cls.sequential,
                    parent_location=cls.sequential.location,
                    category='vertical',
                    modulestore=cls.store,
                    publish_item=False,
                )

                cls.lc_block = ItemFactory.create(
                    category="library_content",
                    parent=cls.vertical,
                    parent_location=cls.vertical.location,
                    max_count=2,
                    source_library_id=unicode(cls.library.location.library_key),
                    modulestore=cls.store,
                )
                # copy children from library to content block (LibaryContentDescriptor.tools.update_children?)
                cls.store.update_item(cls.course, creator.id)
                cls.store.update_item(cls.lc_block, creator.id)
    def test_content_library_export_import(self):
        library1 = LibraryFactory.create(modulestore=self.store)
        source_library1_key = library1.location.library_key
        library2 = LibraryFactory.create(modulestore=self.store)
        source_library2_key = library2.location.library_key

        import_library_from_xml(
            self.store,
            'test_user',
            TEST_DATA_DIR,
            ['library_empty_problem'],
            static_content_store=contentstore(),
            target_id=source_library1_key,
            load_error_modules=False,
            raise_on_failure=True,
            create_if_not_present=True,
        )

        export_library_to_xml(
            self.store,
            contentstore(),
            source_library1_key,
            self.export_dir,
            'exported_source_library',
        )

        source_library = self.store.get_library(source_library1_key)
        self.assertEqual(source_library.url_name, 'library')

        # Import the exported library into a different content library.
        import_library_from_xml(
            self.store,
            'test_user',
            self.export_dir,
            ['exported_source_library'],
            static_content_store=contentstore(),
            target_id=source_library2_key,
            load_error_modules=False,
            raise_on_failure=True,
            create_if_not_present=True,
        )

        # Compare the two content libraries for equality.
        self.assertCoursesEqual(source_library1_key, source_library2_key)
Esempio n. 19
0
    def test_get_libraries(self):
        """ Test get_libraries() """
        libraries = [LibraryFactory.create(modulestore=self.store) for _ in range(0, 3)]
        lib_dict = dict([(lib.location.library_key, lib) for lib in libraries])

        lib_list = self.store.get_libraries()

        self.assertEqual(len(lib_list), len(libraries))
        for lib in lib_list:
            self.assertIn(lib.location.library_key, lib_dict)
Esempio n. 20
0
 def test_xblock_in_lib_have_published_version_returns_false(self):
     library = LibraryFactory.create(modulestore=self.store)
     block = ItemFactory.create(
         category="html",
         parent_location=library.location,
         user_id=self.user_id,
         publish_item=False,
         modulestore=self.store,
     )
     self.assertFalse(self.store.has_published_version(block))
Esempio n. 21
0
 def test_display_with_default_methods(self):
     """
     Check that the display_x_with_default methods have been implemented, for
     compatibility with courses.
     """
     org = "TestOrgX"
     lib_code = "LC101"
     library = LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
     self.assertEqual(library.display_org_with_default, org)
     self.assertEqual(library.display_number_with_default, lib_code)
Esempio n. 22
0
    def test_get_lib_edit_html(self):
        """
        Test that we can get the studio view for editing a library using /library/:key/
        """
        lib = LibraryFactory.create()

        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 200)
        self.assertIn("<html", response.content)
        self.assertIn(lib.display_name, response.content)
Esempio n. 23
0
 def test_get_lib_version(self):
     """
     Test that we can get version data about a library from get_library()
     """
     # Create a library
     lib_key = LibraryFactory.create(modulestore=self.store).location.library_key
     # Re-load the library from the modulestore, explicitly including version information:
     lib = self.store.get_library(lib_key, remove_version=False, remove_branch=False)
     version = lib.location.library_key.version_guid
     self.assertIsInstance(version, ObjectId)
Esempio n. 24
0
 def test_get_component_templates(self):
     """
     Verify that templates for adding discussion and advanced components to
     content libraries are not provided.
     """
     lib = LibraryFactory.create()
     lib.advanced_modules = ['lti']
     lib.save()
     templates = [template['type'] for template in get_component_templates(lib, library=True)]
     self.assertIn('problem', templates)
     self.assertNotIn('discussion', templates)
     self.assertNotIn('advanced', templates)
Esempio n. 25
0
 def test_no_duplicate_libraries(self):
     """
     We should not be able to create multiple libraries with the same key
     """
     lib = LibraryFactory.create()
     lib_key = lib.location.library_key
     response = self.client.ajax_post(LIBRARY_REST_URL, {
         'org': lib_key.org,
         'library': lib_key.library,
         'display_name': "A Duplicate key, same as 'lib'",
     })
     self.assertIn('already a library defined', parse_json(response)['ErrMsg'])
     self.assertEqual(response.status_code, 400)
Esempio n. 26
0
 def test_strip(self):
     """
     Test that library keys coming out of MixedModuleStore are stripped of
     branch and version info by default.
     """
     # Create a library
     lib_key = LibraryFactory.create(modulestore=self.store).location.library_key
     # Re-load the library from the modulestore, explicitly including version information:
     lib = self.store.get_library(lib_key)
     self.assertEqual(lib.location.version_guid, None)
     self.assertEqual(lib.location.branch, None)
     self.assertEqual(lib.location.library_key.version_guid, None)
     self.assertEqual(lib.location.library_key.branch, None)
Esempio n. 27
0
 def test_strip(self):
     """
     Test that library keys coming out of MixedModuleStore are stripped of
     branch and version info by default.
     """
     # Create a library
     lib_key = LibraryFactory.create(
         modulestore=self.store).location.library_key
     # Re-load the library from the modulestore, explicitly including version information:
     lib = self.store.get_library(lib_key)
     self.assertEqual(lib.location.version_guid, None)
     self.assertEqual(lib.location.branch, None)
     self.assertEqual(lib.location.library_key.version_guid, None)
     self.assertEqual(lib.location.library_key.branch, None)
    def setUp(self):
        super(TestTaskExecution, self).setUp()
        SignalHandler.course_published.disconnect(listen_for_course_publish)
        SignalHandler.library_updated.disconnect(listen_for_library_update)
        self.course = CourseFactory.create(start=datetime(2015, 3, 1, tzinfo=UTC))

        self.chapter = ItemFactory.create(
            parent_location=self.course.location,
            category='chapter',
            display_name="Week 1",
            publish_item=True,
            start=datetime(2015, 3, 1, tzinfo=UTC),
        )
        self.sequential = ItemFactory.create(
            parent_location=self.chapter.location,
            category='sequential',
            display_name="Lesson 1",
            publish_item=True,
            start=datetime(2015, 3, 1, tzinfo=UTC),
        )
        self.vertical = ItemFactory.create(
            parent_location=self.sequential.location,
            category='vertical',
            display_name='Subsection 1',
            publish_item=True,
            start=datetime(2015, 4, 1, tzinfo=UTC),
        )
        # unspecified start - should inherit from container
        self.html_unit = ItemFactory.create(
            parent_location=self.vertical.location,
            category="html",
            display_name="Html Content",
            publish_item=False,
        )

        self.library = LibraryFactory.create()

        self.library_block1 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content",
            publish_item=False,
        )

        self.library_block2 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content 2",
            publish_item=False,
        )
Esempio n. 29
0
    def setUp(self):
        super(TestTaskExecution, self).setUp()
        SignalHandler.course_published.disconnect(listen_for_course_publish)
        SignalHandler.library_updated.disconnect(listen_for_library_update)
        self.course = CourseFactory.create(start=datetime(2015, 3, 1, tzinfo=UTC))

        self.chapter = ItemFactory.create(
            parent_location=self.course.location,
            category='chapter',
            display_name="Week 1",
            publish_item=True,
            start=datetime(2015, 3, 1, tzinfo=UTC),
        )
        self.sequential = ItemFactory.create(
            parent_location=self.chapter.location,
            category='sequential',
            display_name="Lesson 1",
            publish_item=True,
            start=datetime(2015, 3, 1, tzinfo=UTC),
        )
        self.vertical = ItemFactory.create(
            parent_location=self.sequential.location,
            category='vertical',
            display_name='Subsection 1',
            publish_item=True,
            start=datetime(2015, 4, 1, tzinfo=UTC),
        )
        # unspecified start - should inherit from container
        self.html_unit = ItemFactory.create(
            parent_location=self.vertical.location,
            category="html",
            display_name="Html Content",
            publish_item=False,
        )

        self.library = LibraryFactory.create()

        self.library_block1 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content",
            publish_item=False,
        )

        self.library_block2 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content 2",
            publish_item=False,
        )
Esempio n. 30
0
    def test_vertical_completion_with_library_content(self):
        library = LibraryFactory.create(modulestore=self.store)
        ItemFactory.create(parent=library, category='problem', publish_item=False, user_id=self.user.id)
        ItemFactory.create(parent=library, category='problem', publish_item=False, user_id=self.user.id)
        ItemFactory.create(parent=library, category='problem', publish_item=False, user_id=self.user.id)
        lib_vertical = ItemFactory.create(parent=self.sequence, category='vertical', publish_item=False)
        library_content_block = ItemFactory.create(
            parent=lib_vertical,
            category='library_content',
            max_count=1,
            source_library_id=str(library.location.library_key),
            user_id=self.user.id,
        )
        library_content_block.refresh_children()
        lib_vertical = self.store.get_item(lib_vertical.location)
        self._bind_course_module(lib_vertical)
        # We need to refetch the library_content_block to retrieve the
        # fresh version from the call to get_item for lib_vertical
        library_content_block = [child for child in lib_vertical.get_children()
                                 if child.scope_ids.block_type == 'library_content'][0]

        ## Ensure the library_content_block is properly set up
        # This is needed so we can call get_child_descriptors
        self._bind_course_module(library_content_block)
        # Make sure the runtime knows that the block's children vary per-user:
        self.assertTrue(library_content_block.has_dynamic_children())
        self.assertEqual(len(library_content_block.children), 3)
        # Check how many children each user will see:
        self.assertEqual(len(library_content_block.get_child_descriptors()), 1)

        # No problems are complete yet
        self.assertFalse(self.completion_service.vertical_is_complete(lib_vertical))

        for block_key in self.block_keys:
            BlockCompletion.objects.submit_completion(
                user=self.user,
                block_key=block_key,
                completion=1.0
            )
        # Library content problems aren't complete yet
        self.assertFalse(self.completion_service.vertical_is_complete(lib_vertical))

        for child in library_content_block.get_child_descriptors():
            BlockCompletion.objects.submit_completion(
                user=self.user,
                block_key=child.scope_ids.usage_id,
                completion=1.0
            )
        self.assertTrue(self.completion_service.vertical_is_complete(lib_vertical))
Esempio n. 31
0
    def setUp(self):
        super(LibraryContentTest, self).setUp()

        self.tools = LibraryToolsService(self.store)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html", self.library, data="Hello world from block {}".format(i)) for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block(
            "library_content", self.vertical, max_count=1, source_library_id=unicode(self.library.location.library_key)
        )
Esempio n. 32
0
 def test_no_duplicate_libraries(self):
     """
     We should not be able to create multiple libraries with the same key
     """
     lib = LibraryFactory.create()
     lib_key = lib.location.library_key
     response = self.client.ajax_post(
         LIBRARY_REST_URL, {
             'org': lib_key.org,
             'library': lib_key.library,
             'display_name': "A Duplicate key, same as 'lib'",
         })
     self.assertIn('already a library defined',
                   parse_json(response)['ErrMsg'])
     self.assertEqual(response.status_code, 400)
Esempio n. 33
0
 def test_get_component_templates(self):
     """
     Verify that templates for adding discussion and advanced components to
     content libraries are not provided.
     """
     lib = LibraryFactory.create()
     lib.advanced_modules = ['lti']
     lib.save()
     templates = [
         template['type']
         for template in get_component_templates(lib, library=True)
     ]
     self.assertIn('problem', templates)
     self.assertNotIn('discussion', templates)
     self.assertNotIn('advanced', templates)
Esempio n. 34
0
    def test_xblock_studio_url(self):

        # Verify course URL
        course_url = u'/course/{}'.format(unicode(self.course.id))
        self.assertEqual(xblock_studio_url(self.course), course_url)

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location,
                                     category='chapter',
                                     display_name="Week 1")
        self.assertEqual(
            xblock_studio_url(chapter),
            u'{}?show={}'.format(course_url, http.urlquote(chapter.location)))

        # Verify sequential URL
        sequential = ItemFactory.create(parent_location=chapter.location,
                                        category='sequential',
                                        display_name="Lesson 1")
        self.assertEqual(
            xblock_studio_url(sequential),
            u'{}?show={}'.format(course_url,
                                 http.urlquote(sequential.location)))

        # Verify unit URL
        vertical = ItemFactory.create(parent_location=sequential.location,
                                      category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical),
                         u'/container/{}'.format(vertical.location))

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location,
                                            category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical),
                         u'/container/{}'.format(child_vertical.location))

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location,
                                   category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))

        # Verify library URL
        library = LibraryFactory.create()
        expected_url = u'/library/{}'.format(
            unicode(library.location.library_key))
        self.assertEqual(xblock_studio_url(library), expected_url)
Esempio n. 35
0
    def test_libraries_on_course_index(self):
        """
        Test getting the list of libraries from the course listing page
        """
        # Add a library:
        lib1 = LibraryFactory.create()

        index_url = "/home/"
        index_response = self.client.get(index_url, {}, HTTP_ACCEPT="text/html")
        parsed_html = lxml.html.fromstring(index_response.content)
        library_link_elements = parsed_html.find_class("library-link")
        self.assertEqual(len(library_link_elements), 1)
        link = library_link_elements[0]
        self.assertEqual(link.get("href"), reverse_library_url("library_handler", lib1.location.library_key))
        # now test that url
        outline_response = self.client.get(link.get("href"), {}, HTTP_ACCEPT="text/html")
        self.assertEqual(outline_response.status_code, 200)
Esempio n. 36
0
    def test_advanced_problem_types(self):
        """
        Verify that advanced problem types are not provided in problem component for libraries.
        """
        lib = LibraryFactory.create()
        lib.save()

        problem_type_templates = next(
            (component['templates'] for component in get_component_templates(lib, library=True) if component['type'] == 'problem'),
            []
        )
        # Each problem template has a category which shows whether problem is a 'problem'
        # or which of the advanced problem type (e.g drag-and-drop-v2).
        problem_type_categories = [problem_template['category'] for problem_template in problem_type_templates]

        for advance_problem_type in settings.ADVANCED_PROBLEM_TYPES:
            self.assertNotIn(advance_problem_type['component'], problem_type_categories)
Esempio n. 37
0
    def test_component_limits(self):
        """
        Test that component limits in libraries are respected.
        """
        with self.settings(MAX_BLOCKS_PER_CONTENT_LIBRARY=1):
            library = LibraryFactory.create()
            data = {
                'parent_locator': str(library.location),
                'category': 'html'
            }
            response = self.client.ajax_post(reverse('xblock_handler'), data)
            self.assertEqual(response.status_code, 200)

            # Adding another component should cause failure:
            response = self.client.ajax_post(reverse('xblock_handler'), data)
            self.assertEqual(response.status_code, 400)
            self.assertIn('cannot have more than 1 component', parse_json(response)['error'])
Esempio n. 38
0
    def test_advanced_problem_types(self):
        """
        Verify that advanced problem types are not provided in problem component for libraries.
        """
        lib = LibraryFactory.create()
        lib.save()

        problem_type_templates = next(
            (component['templates'] for component in get_component_templates(lib, library=True) if component['type'] == 'problem'),
            []
        )
        # Each problem template has a category which shows whether problem is a 'problem'
        # or which of the advanced problem type (e.g drag-and-drop-v2).
        problem_type_categories = [problem_template['category'] for problem_template in problem_type_templates]

        for advance_problem_type in settings.ADVANCED_PROBLEM_TYPES:
            self.assertNotIn(advance_problem_type['component'], problem_type_categories)
Esempio n. 39
0
 def test_delete_item(self):
     """
     Test to make sure delete_item() works on blocks in a library
     """
     library = LibraryFactory.create(modulestore=self.store)
     lib_key = library.location.library_key
     block = ItemFactory.create(
         category="html",
         parent_location=library.location,
         user_id=self.user_id,
         publish_item=False,
         modulestore=self.store,
     )
     library = self.store.get_library(lib_key)
     assert len(library.children) == 1
     self.store.delete_item(block.location, self.user_id)
     library = self.store.get_library(lib_key)
     assert len(library.children) == 0
Esempio n. 40
0
    def test_list_libraries(self):
        """
        Test that we can GET /library/ to list all libraries visible to the current user.
        """
        # Create some more libraries
        libraries = [LibraryFactory.create() for _ in range(3)]
        lib_dict = dict([(lib.location.library_key, lib) for lib in libraries])

        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        lib_list = parse_json(response)
        self.assertEqual(len(lib_list), len(libraries))
        for entry in lib_list:
            self.assertIn("library_key", entry)
            self.assertIn("display_name", entry)
            key = CourseKey.from_string(entry["library_key"])
            self.assertIn(key, lib_dict)
            self.assertEqual(entry["display_name"], lib_dict[key].display_name)
            del lib_dict[key]  # To ensure no duplicates are matched
Esempio n. 41
0
    def setUp(self):
        super().setUp()

        self.tools = LibraryToolsService(self.store, self.user_id)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html", self.library, data=f"Hello world from block {i}")
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block(
            "library_content",
            self.vertical,
            max_count=1,
            source_library_id=str(self.library.location.library_key)
        )
    def setUp(self):
        super(LibraryContentTest, self).setUp()

        self.tools = LibraryToolsService(self.store)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html", self.library, data="Hello world from block {}".format(i))
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block(
            "library_content",
            self.vertical,
            max_count=1,
            source_libraries=[LibraryVersionReference(self.library.location.library_key)]
        )
Esempio n. 43
0
    def test_get_lib_info(self):
        """
        Test that we can get data about a library (in JSON format) using /library/:key/
        """
        # Create a library
        lib_key = LibraryFactory.create().location.library_key
        # Re-load the library from the modulestore, explicitly including version information:
        lib = self.store.get_library(lib_key, remove_version=False, remove_branch=False)
        version = lib.location.library_key.version_guid
        self.assertNotEqual(version, None)

        response = self.client.get_json(make_url_for_lib(lib_key))
        self.assertEqual(response.status_code, 200)
        info = parse_json(response)
        self.assertEqual(info['display_name'], lib.display_name)
        self.assertEqual(info['library_id'], unicode(lib_key))
        self.assertEqual(info['previous_version'], None)
        self.assertNotEqual(info['version'], None)
        self.assertNotEqual(info['version'], '')
        self.assertEqual(info['version'], unicode(version))
    def setUp(self):
        super(LibraryContentTest, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments

        self.tools = LibraryToolsService(self.store, self.user_id)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html",
                            self.library,
                            data="Hello world from block {}".format(i))
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block("library_content",
                                        self.vertical,
                                        max_count=1,
                                        source_library_id=six.text_type(
                                            self.library.location.library_key))
Esempio n. 45
0
    def setup_course_base(self, store):
        """
        Set up the for the course outline tests.
        """
        self.library = LibraryFactory.create(modulestore=store)

        self.html_unit1 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content",
            modulestore=store,
            publish_item=False,
        )

        self.html_unit2 = ItemFactory.create(
            parent_location=self.library.location,
            category="html",
            display_name="Html Content 2",
            modulestore=store,
            publish_item=False,
        )
Esempio n. 46
0
    def test_libraries_on_course_index(self):
        """
        Test getting the list of libraries from the course listing page
        """
        # Add a library:
        lib1 = LibraryFactory.create()

        index_url = '/home/'
        index_response = self.client.get(index_url, {},
                                         HTTP_ACCEPT='text/html')
        parsed_html = lxml.html.fromstring(index_response.content)
        library_link_elements = parsed_html.find_class('library-link')
        self.assertEqual(len(library_link_elements), 1)
        link = library_link_elements[0]
        self.assertEqual(
            link.get("href"),
            reverse_library_url('library_handler', lib1.location.library_key),
        )
        # now test that url
        outline_response = self.client.get(link.get("href"), {},
                                           HTTP_ACCEPT='text/html')
        self.assertEqual(outline_response.status_code, 200)
Esempio n. 47
0
    def test_block_with_children(self):
        """
        Test that blocks used from a library can have children.
        """
        library = LibraryFactory.create(modulestore=self.store)

        # In the library, create a vertical block with a child:
        vert_block = ItemFactory.create(
            category="vertical",
            parent_location=library.location,
            user_id=self.user_id,
            publish_item=False,
            modulestore=self.store,
        )
        child_block = ItemFactory.create(
            category="html",
            parent_location=vert_block.location,
            user_id=self.user_id,
            publish_item=False,
            metadata={"data": "Hello world", },
            modulestore=self.store,
        )
        assert child_block.parent.replace(version_guid=None, branch=None) == vert_block.location
Esempio n. 48
0
    def test_library_author_view_with_paging(self):
        """
        Test that LibraryRoot.author_view can apply paging
        We have to patch the runtime (module system) in order to be able to
        render blocks in our test environment.
        """
        library = LibraryFactory.create(modulestore=self.store)
        # Add five HTML blocks to the library:
        blocks = [
            ItemFactory.create(category="html",
                               parent_location=library.location,
                               user_id=self.user_id,
                               publish_item=False,
                               modulestore=self.store,
                               data="HtmlBlock" + str(i)) for i in range(5)
        ]
        library = self.store.get_library(library.location.library_key)

        def render_and_check_contents(page, page_size):
            """ Renders block and asserts on returned content """
            context = {
                'reorderable_items': set(),
                'paging': {
                    'page_number': page,
                    'page_size': page_size
                }
            }
            expected_blocks = blocks[page_size * page:page_size * (page + 1)]
            result = library.render(AUTHOR_VIEW, context)

            for expected_block in expected_blocks:
                self.assertIn(expected_block.data, result.content)

        render_and_check_contents(0, 3)
        render_and_check_contents(1, 3)
        render_and_check_contents(0, 2)
        render_and_check_contents(1, 2)
Esempio n. 49
0
    def test_copy_from_template_publish(self):
        """
        Test that copy_from_template's "defaults" data is not lost
        when blocks are published.
        """
        # Create a library with a problem:
        source_library = LibraryFactory.create(modulestore=self.store)
        display_name_expected = "CUSTOM Library Display Name"
        self.make_block("problem",
                        source_library,
                        display_name=display_name_expected)
        # Reload source_library since we need its branch and version to use copy_from_template:
        source_library = self.store.get_library(
            source_library.location.library_key,
            remove_version=False,
            remove_branch=False)
        # And a course with a vertical:
        course = CourseFactory.create(modulestore=self.store)
        self.make_block("vertical", course)

        problem_key_in_course = self.store.copy_from_template(
            source_library.children,
            dest_key=course.location,
            user_id=self.user_id)[0]

        # We do the following twice because different methods get used inside
        # split modulestore on first vs. subsequent publish
        for __ in range(2):
            # Publish:
            self.store.publish(problem_key_in_course, self.user_id)
            # Test that the defaults values are there.
            problem_published = self.store.get_item(
                problem_key_in_course.for_branch(
                    ModuleStoreEnum.BranchName.published))
            self.assertEqual(problem_published.display_name,
                             display_name_expected)
Esempio n. 50
0
    def test_update_item(self):
        """
        Test that update_item works for a block in a library
        """
        library = LibraryFactory.create(modulestore=self.store)

        block = ItemFactory.create(
            category="html",
            parent_location=library.location,
            user_id=self.user_id,
            publish_item=False,
            metadata={"data": "Hello world", },
            modulestore=self.store,
        )
        block_key = block.location
        block.data = "NEW"
        old_version = self.store.get_item(block_key, remove_version=False, remove_branch=False).location.version_guid
        self.store.update_item(block, self.user_id)
        # Reload block from the modulestore
        block = self.store.get_item(block_key)
        assert block.data == 'NEW'
        assert block.location == block_key
        new_version = self.store.get_item(block_key, remove_version=False, remove_branch=False).location.version_guid
        assert old_version != new_version
Esempio n. 51
0
    def test_library_import(self):
        """
        Try importing a known good library archive, and verify that the
        contents of the library have completely replaced the old contents.
        """
        # Create some blocks to overwrite
        library = LibraryFactory.create(modulestore=self.store)
        lib_key = library.location.library_key
        test_block = ItemFactory.create(
            category="vertical",
            parent_location=library.location,
            user_id=self.user.id,
            publish_item=False,
        )
        test_block2 = ItemFactory.create(category="vertical",
                                         parent_location=library.location,
                                         user_id=self.user.id,
                                         publish_item=False)
        # Create a library and blocks that should remain unmolested.
        unchanged_lib = LibraryFactory.create()
        unchanged_key = unchanged_lib.location.library_key
        test_block3 = ItemFactory.create(
            category="vertical",
            parent_location=unchanged_lib.location,
            user_id=self.user.id,
            publish_item=False)
        test_block4 = ItemFactory.create(
            category="vertical",
            parent_location=unchanged_lib.location,
            user_id=self.user.id,
            publish_item=False)
        # Refresh library.
        library = self.store.get_library(lib_key)
        children = [
            self.store.get_item(child).url_name for child in library.children
        ]
        self.assertEqual(len(children), 2)
        self.assertIn(test_block.url_name, children)
        self.assertIn(test_block2.url_name, children)

        unchanged_lib = self.store.get_library(unchanged_key)
        children = [
            self.store.get_item(child).url_name
            for child in unchanged_lib.children
        ]
        self.assertEqual(len(children), 2)
        self.assertIn(test_block3.url_name, children)
        self.assertIn(test_block4.url_name, children)

        extract_dir = path(tempfile.mkdtemp(dir=settings.DATA_DIR))
        # the extract_dir needs to be passed as a relative dir to
        # import_library_from_xml
        extract_dir_relative = path.relpath(extract_dir, settings.DATA_DIR)

        try:
            with tarfile.open(
                    path(TEST_DATA_DIR) / 'imports' /
                    'library.HhJfPD.tar.gz') as tar:
                safetar_extractall(tar, extract_dir)
            library_items = import_library_from_xml(
                self.store,
                self.user.id,
                settings.GITHUB_REPO_ROOT, [extract_dir_relative / 'library'],
                load_error_modules=False,
                static_content_store=contentstore(),
                target_id=lib_key)
        finally:
            shutil.rmtree(extract_dir)

        self.assertEqual(lib_key, library_items[0].location.library_key)
        library = self.store.get_library(lib_key)
        children = [
            self.store.get_item(child).url_name for child in library.children
        ]
        self.assertEqual(len(children), 3)
        self.assertNotIn(test_block.url_name, children)
        self.assertNotIn(test_block2.url_name, children)

        unchanged_lib = self.store.get_library(unchanged_key)
        children = [
            self.store.get_item(child).url_name
            for child in unchanged_lib.children
        ]
        self.assertEqual(len(children), 2)
        self.assertIn(test_block3.url_name, children)
        self.assertIn(test_block4.url_name, children)
Esempio n. 52
0
    def test_end_to_end(self):
        """
        Test the happy path of the backfill command without any mocking.
        """
        # org_A: already existing, with courses and a library.
        org_a = add_organization({"short_name": "org_A", "name": "Org A"})
        course_a1_key = CourseOverviewFactory(org="org_A", run="1").id
        CourseOverviewFactory(org="org_A", run="2")
        LibraryFactory(org="org_A")

        # Write linkage for org_a->course_a1.
        # (Linkage for org_a->course_a2 is purposefully left out here;
        # it should be created by the backfill).
        add_organization_course(org_a, course_a1_key)

        # org_B: already existing, but has no content.
        add_organization({"short_name": "org_B", "name": "Org B"})

        # org_C: has a couple courses; should be created.
        CourseOverviewFactory(org="org_C", run="1")
        CourseOverviewFactory(org="org_C", run="2")

        # org_D: has both a course and a library; should be created.
        CourseOverviewFactory(org="org_D", run="1")
        LibraryFactory(org="org_D")

        # org_E: just has a library; should be created.
        LibraryFactory(org="org_E")

        # Confirm starting condition:
        # Only orgs are org_A and org_B, and only linkage is org_a->course_a1.
        assert set(org["short_name"]
                   for org in get_organizations()) == {"org_A", "org_B"}
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_A'))) == 1
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_B'))) == 0

        # Run the backfill.
        call_command("backfill_orgs_and_org_courses", "--apply")

        # Confirm ending condition:
        # All five orgs present. Each org a has expected number of org-course linkages.
        assert set(org["short_name"] for org in get_organizations()) == {
            "org_A", "org_B", "org_C", "org_D", "org_E"
        }
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_A'))) == 2
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_B'))) == 0
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_C'))) == 2
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_D'))) == 1
        assert len(
            get_organization_courses(
                get_organization_by_short_name('org_E'))) == 0
Esempio n. 53
0
    def test_end_to_end(self, run_type):
        """
        Test the happy path of the backfill command without any mocking.
        """
        # org_A: already existing, with courses and a library.
        org_a = add_organization({"short_name": "org_A", "name": "Org A"})
        course_a1_key = CourseOverviewFactory(org="org_A", run="1").id
        CourseOverviewFactory(org="org_A", run="2")
        LibraryFactory(org="org_A")

        # Write linkage for org_a->course_a1.
        # (Linkage for org_a->course_a2 is purposefully left out here;
        # it should be created by the backfill).
        add_organization_course(org_a, course_a1_key)

        # org_B: already existing, but has no content.
        add_organization({"short_name": "org_B", "name": "Org B"})

        # org_C: has a few courses; should be created.
        CourseOverviewFactory(org="org_C", run="1")
        CourseOverviewFactory(org="org_C", run="2")
        # Include an Old Mongo Modulestore -style deprecated course key.
        # This can be safely removed when Old Mongo Modulestore support is
        # removed.
        CourseOverviewFactory(
            id=CourseLocator.from_string("org_C/toy/3"),
            org="org_C",
            run="3",
        )

        # org_D: has both a course and a library; should be created.
        CourseOverviewFactory(org="org_D", run="1")
        LibraryFactory(org="org_D")

        # org_E: just has a library; should be created.
        LibraryFactory(org="org_E")

        # Confirm starting condition:
        # Only orgs are org_A and org_B, and only linkage is org_a->course_a1.
        assert set(
            org["short_name"] for org in get_organizations()
        ) == {
            "org_A", "org_B"
        }
        assert len(get_organization_courses(get_organization_by_short_name('org_A'))) == 1
        assert len(get_organization_courses(get_organization_by_short_name('org_B'))) == 0

        # Run the backfill.
        call_command("backfill_orgs_and_org_courses", run_type)

        if run_type == "--dry":
            # Confirm ending conditions are the same as the starting conditions.
            assert set(
                org["short_name"] for org in get_organizations()
            ) == {
                "org_A", "org_B"
            }
            assert len(get_organization_courses(get_organization_by_short_name('org_A'))) == 1
            assert len(get_organization_courses(get_organization_by_short_name('org_B'))) == 0
        else:
            # Confirm ending condition:
            # All five orgs present. Each org a has expected number of org-course linkages.
            assert set(
                org["short_name"] for org in get_organizations()
            ) == {
                "org_A", "org_B", "org_C", "org_D", "org_E"
            }
            assert len(get_organization_courses(get_organization_by_short_name('org_A'))) == 2
            assert len(get_organization_courses(get_organization_by_short_name('org_B'))) == 0
            assert len(get_organization_courses(get_organization_by_short_name('org_C'))) == 3
            assert len(get_organization_courses(get_organization_by_short_name('org_D'))) == 1
            assert len(get_organization_courses(get_organization_by_short_name('org_E'))) == 0
Esempio n. 54
0
 def test_get_library_keys(self):
     """ Test get_library_keys() """
     libraries = [LibraryFactory.create(modulestore=self.store) for _ in range(3)]
     lib_keys_expected = {lib.location.library_key for lib in libraries}
     lib_keys_actual = set(self.store.get_library_keys())
     assert lib_keys_expected == lib_keys_actual
Esempio n. 55
0
    def test_vertical_completion_with_library_content(self):
        library = LibraryFactory.create(modulestore=self.store)
        ItemFactory.create(parent=library,
                           category='problem',
                           publish_item=False,
                           user_id=self.user.id)
        ItemFactory.create(parent=library,
                           category='problem',
                           publish_item=False,
                           user_id=self.user.id)
        ItemFactory.create(parent=library,
                           category='problem',
                           publish_item=False,
                           user_id=self.user.id)
        # Create a new vertical to hold the library content block
        # It is very important that we use parent_location=self.sequence.location (and not parent=self.sequence), since
        # sequence is a class attribute and passing it by value will update its .children=[] which will then leak into
        # other tests and cause errors if the children no longer exist.
        lib_vertical = ItemFactory.create(
            parent_location=self.sequence.location,
            category='vertical',
            publish_item=False,
        )
        library_content_block = ItemFactory.create(
            parent=lib_vertical,
            category='library_content',
            max_count=1,
            source_library_id=str(library.location.library_key),
            user_id=self.user.id,
        )
        library_content_block.refresh_children()
        lib_vertical = self.store.get_item(lib_vertical.location)
        self._bind_course_module(lib_vertical)
        # We need to refetch the library_content_block to retrieve the
        # fresh version from the call to get_item for lib_vertical
        library_content_block = [
            child for child in lib_vertical.get_children()
            if child.scope_ids.block_type == 'library_content'
        ][0]

        ## Ensure the library_content_block is properly set up
        # This is needed so we can call get_child_descriptors
        self._bind_course_module(library_content_block)
        # Make sure the runtime knows that the block's children vary per-user:
        assert library_content_block.has_dynamic_children()
        assert len(library_content_block.children) == 3
        # Check how many children each user will see:
        assert len(library_content_block.get_child_descriptors()) == 1

        # No problems are complete yet
        assert not self.completion_service.vertical_is_complete(lib_vertical)

        for block_key in self.block_keys:
            BlockCompletion.objects.submit_completion(user=self.user,
                                                      block_key=block_key,
                                                      completion=1.0)
        # Library content problems aren't complete yet
        assert not self.completion_service.vertical_is_complete(lib_vertical)

        for child in library_content_block.get_child_descriptors():
            BlockCompletion.objects.submit_completion(
                user=self.user,
                block_key=child.scope_ids.usage_id,
                completion=1.0)
        assert self.completion_service.vertical_is_complete(lib_vertical)