def test_course_listing_performance(self, store, courses_list_from_group_calls, courses_list_calls):
        """
        Create large number of courses and give access of some of these courses to the user and
        compare the time to fetch accessible courses for the user through traversing all courses and
        reversing django groups
        """
        # create list of random course numbers which will be accessible to the user
        user_course_ids = random.sample(range(TOTAL_COURSES_COUNT), USER_COURSES_COUNT)

        # create courses and assign those to the user which have their number in user_course_ids
        with self.store.default_store(store):
            for number in range(TOTAL_COURSES_COUNT):
                org = 'Org{0}'.format(number)
                course = 'Course{0}'.format(number)
                run = 'Run{0}'.format(number)
                course_location = self.store.make_course_key(org, course, run)
                if number in user_course_ids:
                    self._create_course_with_access_groups(course_location, self.user, store=store)
                else:
                    self._create_course_with_access_groups(course_location, store=store)

        # time the get courses by iterating through all courses
        with Timer() as iteration_over_courses_time_1:
            courses_iter, __ = _accessible_courses_iter(self.request)
        self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)

        # time again the get courses by iterating through all courses
        with Timer() as iteration_over_courses_time_2:
            courses_iter, __ = _accessible_courses_iter(self.request)
        self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)

        # time the get courses by reversing django groups
        with Timer() as iteration_over_groups_time_1:
            courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), USER_COURSES_COUNT)

        # time again the get courses by reversing django groups
        with Timer() as iteration_over_groups_time_2:
            courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), USER_COURSES_COUNT)

        # TODO (cdyer) : iteration over courses was optimized, and is now
        # sometimes faster than iteration over groups. One of the following
        # should be done to resolve this:
        # * Iteration over groups should be sped up.
        # * Iteration over groups should be removed, as it no longer saves time.
        # * Or this part of the test should be removed.

        # Test that the time taken by getting courses through reversing django
        # groups is lower then the time taken by traversing through all courses
        # (if accessible courses are relatively small).
        #self.assertGreaterEqual(iteration_over_courses_time_1.elapsed, iteration_over_groups_time_1.elapsed)
        #self.assertGreaterEqual(iteration_over_courses_time_2.elapsed, iteration_over_groups_time_2.elapsed)

        # Now count the db queries
        with check_mongo_calls(courses_list_from_group_calls):
            _accessible_courses_list_from_groups(self.request)

        with check_mongo_calls(courses_list_calls):
            list(_accessible_courses_iter(self.request))
    def test_course_listing_performance(self, store, courses_list_from_group_calls, courses_list_calls):
        """
        Create large number of courses and give access of some of these courses to the user and
        compare the time to fetch accessible courses for the user through traversing all courses and
        reversing django groups
        """
        # create list of random course numbers which will be accessible to the user
        user_course_ids = random.sample(range(TOTAL_COURSES_COUNT), USER_COURSES_COUNT)

        # create courses and assign those to the user which have their number in user_course_ids
        with self.store.default_store(store):
            for number in range(TOTAL_COURSES_COUNT):
                org = 'Org{0}'.format(number)
                course = 'Course{0}'.format(number)
                run = 'Run{0}'.format(number)
                course_location = self.store.make_course_key(org, course, run)
                if number in user_course_ids:
                    self._create_course_with_access_groups(course_location, self.user, store=store)
                else:
                    self._create_course_with_access_groups(course_location, store=store)

        # time the get courses by iterating through all courses
        with Timer() as iteration_over_courses_time_1:
            courses_iter, __ = _accessible_courses_iter(self.request)
        self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)

        # time again the get courses by iterating through all courses
        with Timer() as iteration_over_courses_time_2:
            courses_iter, __ = _accessible_courses_iter(self.request)
        self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)

        # time the get courses by reversing django groups
        with Timer() as iteration_over_groups_time_1:
            courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), USER_COURSES_COUNT)

        # time again the get courses by reversing django groups
        with Timer() as iteration_over_groups_time_2:
            courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), USER_COURSES_COUNT)

        # TODO (cdyer) : iteration over courses was optimized, and is now
        # sometimes faster than iteration over groups. One of the following
        # should be done to resolve this:
        # * Iteration over groups should be sped up.
        # * Iteration over groups should be removed, as it no longer saves time.
        # * Or this part of the test should be removed.

        # Test that the time taken by getting courses through reversing django
        # groups is lower then the time taken by traversing through all courses
        # (if accessible courses are relatively small).
        #self.assertGreaterEqual(iteration_over_courses_time_1.elapsed, iteration_over_groups_time_1.elapsed)
        #self.assertGreaterEqual(iteration_over_courses_time_2.elapsed, iteration_over_groups_time_2.elapsed)

        # Now count the db queries
        with check_mongo_calls(courses_list_from_group_calls):
            _accessible_courses_list_from_groups(self.request)

        with check_mongo_calls(courses_list_calls):
            list(_accessible_courses_iter(self.request))
示例#3
0
    def test_get_course_list_with_invalid_course_location(self, store):
        """
        Test getting courses with invalid course location (course deleted from modulestore).
        """
        with self.store.default_store(store):
            course_key = self.store.make_course_key('Org', 'Course', 'Run')
            self._create_course_with_access_groups(course_key, self.user,
                                                   store)

        # get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)
        courses_list = list(courses_iter)
        self.assertEqual(len(courses_list), 1)

        courses_summary_iter, __ = _accessible_courses_summary_iter(
            self.request)
        courses_summary_list = list(courses_summary_iter)

        # Verify fetched accessible courses list is a list of CourseSummery instances and only one course
        # is returned
        self.assertTrue(
            all(
                isinstance(course, CourseSummary)
                for course in courses_summary_list))
        self.assertEqual(len(courses_summary_list), 1)

        # get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(
            self.request)
        self.assertEqual(len(courses_list_by_groups), 1)

        # check course lists have same courses
        self.assertEqual(courses_list, courses_list_by_groups)

        # now delete this course and re-add user to instructor group of this course
        delete_course(course_key, self.user.id)

        CourseInstructorRole(course_key).add_users(self.user)

        # Get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)

        # Get course summaries by iterating all courses
        courses_summary_iter, __ = _accessible_courses_summary_iter(
            self.request)

        # Get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(
            self.request)

        # Test that course list returns no course
        self.assertEqual([
            len(list(courses_iter)),
            len(courses_list_by_groups),
            len(list(courses_summary_iter))
        ], [0, 0, 0])
示例#4
0
    def test_errored_course_regular_access(self, store, path_to_patch):
        """
        Test the course list for regular staff when get_course returns an ErrorDescriptor
        """
        GlobalStaff().remove_users(self.user)

        with self.store.default_store(store):
            CourseStaffRole(
                self.store.make_course_key('Non', 'Existent',
                                           'Course')).add_users(self.user)

            course_key = self.store.make_course_key('Org1', 'Course1', 'Run1')
            self._create_course_with_access_groups(course_key, self.user,
                                                   store)

            with patch(path_to_patch, Mock(side_effect=Exception)):
                self.assertIsInstance(self.store.get_course(course_key),
                                      ErrorDescriptor)

                # get courses through iterating all courses
                courses_iter, __ = _accessible_courses_iter(self.request)
                courses_list = list(courses_iter)
                self.assertEqual(courses_list, [])

                # get courses by reversing group name formats
                courses_list_by_groups, __ = _accessible_courses_list_from_groups(
                    self.request)
                self.assertEqual(courses_list_by_groups, [])
                self.assertEqual(courses_list, courses_list_by_groups)
    def test_get_course_list_with_invalid_course_location(self, store):
        """
        Test getting courses with invalid course location (course deleted from modulestore).
        """
        with self.store.default_store(store):
            course_key = self.store.make_course_key('Org', 'Course', 'Run')
            self._create_course_with_access_groups(course_key, self.user, store)

        # get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)
        courses_list = list(courses_iter)
        self.assertEqual(len(courses_list), 1)

        courses_summary_iter, __ = _accessible_courses_summary_iter(self.request)
        courses_summary_list = list(courses_summary_iter)

        # Verify fetched accessible courses list is a list of CourseSummery instances and only one course
        # is returned
        self.assertTrue(all(isinstance(course, CourseSummary) for course in courses_summary_list))
        self.assertEqual(len(courses_summary_list), 1)

        # get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list_by_groups), 1)

        # check course lists have same courses
        self.assertEqual(courses_list, courses_list_by_groups)

        # now delete this course and re-add user to instructor group of this course
        delete_course(course_key, self.user.id)

        CourseInstructorRole(course_key).add_users(self.user)

        # Get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)

        # Get course summaries by iterating all courses
        courses_summary_iter, __ = _accessible_courses_summary_iter(self.request)

        # Get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)

        # Test that course list returns no course
        self.assertEqual(
            [len(list(courses_iter)), len(courses_list_by_groups), len(list(courses_summary_iter))],
            [0, 0, 0]
        )
    def test_errored_course_global_staff(self, store, path_to_patch):
        """
        Test the course list for global staff when get_course returns an ErrorDescriptor
        """
        GlobalStaff().add_users(self.user)

        with self.store.default_store(store):
            course_key = self.store.make_course_key('Org1', 'Course1', 'Run1')
            self._create_course_with_access_groups(course_key, self.user, store=store)

            with patch(path_to_patch, Mock(side_effect=Exception)):
                self.assertIsInstance(self.store.get_course(course_key), ErrorDescriptor)

                # get courses through iterating all courses
                courses_iter, __ = _accessible_courses_iter(self.request)
                self.assertEqual(list(courses_iter), [])

                # get courses by reversing group name formats
                courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
                self.assertEqual(courses_list_by_groups, [])
    def test_get_course_list(self):
        """
        Test getting courses with new access group format e.g. 'instructor_edx.course.run'
        """
        course_location = self.store.make_course_key('Org1', 'Course1', 'Run1')
        self._create_course_with_access_groups(course_location, self.user)

        # get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)
        courses_list = list(courses_iter)
        self.assertEqual(len(courses_list), 1)

        courses_summary_list, __ = _accessible_courses_summary_iter(self.request)
        self.assertEqual(len(list(courses_summary_list)), 1)

        # get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list_by_groups), 1)

        # check both course lists have same courses
        self.assertEqual(courses_list, courses_list_by_groups)
    def test_get_course_list(self):
        """
        Test getting courses with new access group format e.g. 'instructor_edx.course.run'
        """
        course_location = self.store.make_course_key('Org1', 'Course1', 'Run1')
        self._create_course_with_access_groups(course_location, self.user)

        # get courses through iterating all courses
        courses_iter, __ = _accessible_courses_iter(self.request)
        courses_list = list(courses_iter)
        self.assertEqual(len(courses_list), 1)

        courses_summary_list, __ = _accessible_courses_summary_iter(self.request)
        self.assertEqual(len(list(courses_summary_list)), 1)

        # get courses by reversing group name formats
        courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list_by_groups), 1)

        # check both course lists have same courses
        self.assertEqual(courses_list, courses_list_by_groups)
    def test_courses_list_with_ccx_courses(self):
        """
        Tests that CCX courses are filtered in course listing.
        """
        # Create a course and assign access roles to user.
        course_location = self.store.make_course_key('Org1', 'Course1', 'Run1')
        course = self._create_course_with_access_groups(course_location, self.user)

        # Create a ccx course key and add assign access roles to user.
        ccx_course_key = CCXLocator.from_course_locator(course.id, '1')
        self._add_role_access_to_user(self.user, ccx_course_key)

        # Test that CCX courses are filtered out.
        courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), 1)
        self.assertNotIn(
            ccx_course_key,
            [course.id for course in courses_list]
        )

        # Get all courses which user has access.
        instructor_courses = UserBasedRole(self.user, CourseInstructorRole.ROLE).courses_with_role()
        staff_courses = UserBasedRole(self.user, CourseStaffRole.ROLE).courses_with_role()
        all_courses = (instructor_courses | staff_courses)

        # Verify that CCX course exists in access but filtered by `_accessible_courses_list_from_groups`.
        self.assertIn(
            ccx_course_key,
            [access.course_id for access in all_courses]
        )

        # Verify that CCX courses are filtered out while iterating over all courses
        mocked_ccx_course = Mock(id=ccx_course_key)
        with patch('xmodule.modulestore.mixed.MixedModuleStore.get_courses', return_value=[mocked_ccx_course]):
            courses_iter, __ = _accessible_courses_iter(self.request)
            self.assertEqual(len(list(courses_iter)), 0)
    def test_courses_list_with_ccx_courses(self):
        """
        Tests that CCX courses are filtered in course listing.
        """
        # Create a course and assign access roles to user.
        course_location = self.store.make_course_key('Org1', 'Course1', 'Run1')
        course = self._create_course_with_access_groups(course_location, self.user)

        # Create a ccx course key and add assign access roles to user.
        ccx_course_key = CCXLocator.from_course_locator(course.id, '1')
        self._add_role_access_to_user(self.user, ccx_course_key)

        # Test that CCX courses are filtered out.
        courses_list, __ = _accessible_courses_list_from_groups(self.request)
        self.assertEqual(len(courses_list), 1)
        self.assertNotIn(
            ccx_course_key,
            [course.id for course in courses_list]
        )

        # Get all courses which user has access.
        instructor_courses = UserBasedRole(self.user, CourseInstructorRole.ROLE).courses_with_role()
        staff_courses = UserBasedRole(self.user, CourseStaffRole.ROLE).courses_with_role()
        all_courses = (instructor_courses | staff_courses)

        # Verify that CCX course exists in access but filtered by `_accessible_courses_list_from_groups`.
        self.assertIn(
            ccx_course_key,
            [access.course_id for access in all_courses]
        )

        # Verify that CCX courses are filtered out while iterating over all courses
        mocked_ccx_course = Mock(id=ccx_course_key)
        with patch('xmodule.modulestore.mixed.MixedModuleStore.get_courses', return_value=[mocked_ccx_course]):
            courses_iter, __ = _accessible_courses_iter(self.request)
            self.assertEqual(len(list(courses_iter)), 0)
示例#11
0
 def list(self, request, *args, **kwargs):
     course_runs, __ = _accessible_courses_iter(request)
     page = self.paginate_queryset(list(course_runs))
     serializer = self.get_serializer(page, many=True)
     return self.get_paginated_response(serializer.data)
示例#12
0
 def list(self, request, *args, **kwargs):
     course_runs, __ = _accessible_courses_iter(request)
     page = self.paginate_queryset(list(course_runs))
     serializer = self.get_serializer(page, many=True)
     return self.get_paginated_response(serializer.data)