Ejemplo n.º 1
0
    def test_course_overview_caching(self, modulestore_type, min_mongo_calls,
                                     max_mongo_calls):
        """
        Tests that CourseOverview structures are actually getting cached.

        Arguments:
            modulestore_type (ModuleStoreEnum.Type): type of store to create the
                course in.
            min_mongo_calls (int): minimum number of MongoDB queries we expect
                to be made.
            max_mongo_calls (int): maximum number of MongoDB queries we expect
                to be made.
        """
        course = CourseFactory.create(default_store=modulestore_type)

        # The first time we load a CourseOverview, it will be a cache miss, so
        # we expect the modulestore to be queried.
        with check_mongo_calls_range(max_finds=max_mongo_calls,
                                     min_finds=min_mongo_calls):
            _course_overview_1 = CourseOverview.get_from_id(course.id)

        # The second time we load a CourseOverview, it will be a cache hit, so
        # we expect no modulestore queries to be made.
        with check_mongo_calls(0):
            _course_overview_2 = CourseOverview.get_from_id(course.id)
Ejemplo n.º 2
0
 def test_query_counts_with_multiple_reverification_blocks(self):
     # Total of two ICRV blocks (one created in setup method)
     # Additional call to load each ICRV block
     ItemFactory.create(parent=self.verticals[3],
                        category='edx-reverification-block')
     with check_mongo_calls_range(max_finds=6, max_sends=3):
         self._update_partitions(reload_items=False)
Ejemplo n.º 3
0
 def test_request_global_staff_courses_using_scope(self):
     GlobalStaff().add_users(self.user)
     with check_mongo_calls_range(min_finds=1):
         claims = self.get_with_scope('course_staff')
     courses = claims['staff_courses']
     self.assertIn(self.course_id, courses)
     self.assertEqual(len(courses), 1)
Ejemplo n.º 4
0
    def test_query_counts_with_no_reverification_blocks(self):
        # Delete the ICRV block, so the number of ICRV blocks is zero
        self.store.delete_item(
            self.icrv.location,
            ModuleStoreEnum.UserID.test,
            revision=ModuleStoreEnum.RevisionOption.published_only)

        # 2 calls: get the course (definitions + structures)
        # 2 calls: look up ICRV blocks in the course (definitions + structures)
        with check_mongo_calls_range(max_finds=4, max_sends=2):
            self._update_partitions(reload_items=False)
Ejemplo n.º 5
0
    def test_request_global_staff_courses_with_claims(self):
        GlobalStaff().add_users(self.user)

        values = [self.course_id, 'some_invalid_course']
        with check_mongo_calls_range(min_finds=1):
            claims = self.get_with_claim_value('course_staff', 'staff_courses', values)
        self.assertEqual(len(claims), 2)

        courses = claims['staff_courses']
        self.assertIn(self.course_id, courses)
        self.assertEqual(len(courses), 1)
    def test_query_counts_with_no_reverification_blocks(self):
        # Delete the ICRV block, so the number of ICRV blocks is zero
        self.store.delete_item(
            self.icrv.location,
            ModuleStoreEnum.UserID.test,
            revision=ModuleStoreEnum.RevisionOption.published_only
        )

        # 2 calls: get the course (definitions + structures)
        # 2 calls: look up ICRV blocks in the course (definitions + structures)
        with check_mongo_calls_range(max_finds=4, max_sends=2):
            self._update_partitions(reload_items=False)
Ejemplo n.º 7
0
    def test_versioning(self, modulestore_type, min_mongo_calls, max_mongo_calls):
        """
        Test that CourseOverviews with old version numbers are thrown out.
        """
        with self.store.default_store(modulestore_type):
            course = CourseFactory.create()
            course_overview = CourseOverview.get_from_id(course.id)
            course_overview.version = CourseOverview.VERSION - 1
            course_overview.save()

            # Because the course overview now has an old version number, it should
            # be thrown out after being loaded from the cache, which results in
            # a call to get_course.
            with check_mongo_calls_range(max_finds=max_mongo_calls, min_finds=min_mongo_calls):
                _course_overview_2 = CourseOverview.get_from_id(course.id)
Ejemplo n.º 8
0
    def test_course_overview_caching(self, modulestore_type, min_mongo_calls, max_mongo_calls):
        """
        Tests that CourseOverview structures are actually getting cached.
        """
        course = CourseFactory.create(
            course="TEST101", org="edX", run="Run1", mobile_available=True, default_store=modulestore_type
        )

        # The first time we load a CourseOverview, it will be a cache miss, so
        # we expect the modulestore to be queried.
        with check_mongo_calls_range(max_finds=max_mongo_calls, min_finds=min_mongo_calls):
            _course_overview_1 = CourseOverview.get_from_id(course.id)

        # The second time we load a CourseOverview, it will be a cache hit, so
        # we expect no modulestore queries to be made.
        with check_mongo_calls(0):
            _course_overview_2 = CourseOverview.get_from_id(course.id)
Ejemplo n.º 9
0
    def test_delete_orphans(self, default_store, max_mongo_calls, min_mongo_calls):
        """
        Test that the orphan handler deletes the orphans
        """
        course = self.create_course_with_orphans(default_store)
        orphan_url = reverse_course_url('orphan_handler', course.id)

        with check_mongo_calls_range(max_mongo_calls, min_mongo_calls):
            self.client.delete(orphan_url)

        orphans = json.loads(
            self.client.get(orphan_url, HTTP_ACCEPT='application/json').content.decode('utf-8')
        )
        self.assertEqual(len(orphans), 0, u"Orphans not deleted {}".format(orphans))

        # make sure that any children with one orphan parent and one non-orphan
        # parent are not deleted
        self.assertTrue(self.store.has_item(course.id.make_usage_key('html', "multi_parent_html")))
Ejemplo n.º 10
0
    def test_delete_orphans(self, default_store, max_mongo_calls, min_mongo_calls):
        """
        Test that the orphan handler deletes the orphans
        """
        course = self.create_course_with_orphans(default_store)
        orphan_url = reverse_course_url('orphan_handler', course.id)

        with check_mongo_calls_range(max_mongo_calls, min_mongo_calls):
            self.client.delete(orphan_url)

        orphans = json.loads(
            self.client.get(orphan_url, HTTP_ACCEPT='application/json').content
        )
        self.assertEqual(len(orphans), 0, "Orphans not deleted {}".format(orphans))

        # make sure that any children with one orphan parent and one non-orphan
        # parent are not deleted
        self.assertTrue(self.store.has_item(course.id.make_usage_key('html', "multi_parent_html")))
Ejemplo n.º 11
0
    def test_course_overview_caching(self, modulestore_type, min_mongo_calls,
                                     max_mongo_calls):
        """
        Tests that CourseOverview structures are actually getting cached.
        """
        course = CourseFactory.create(course="TEST101",
                                      org="edX",
                                      run="Run1",
                                      mobile_available=True,
                                      default_store=modulestore_type)

        # The first time we load a CourseOverview, it will be a cache miss, so
        # we expect the modulestore to be queried.
        with check_mongo_calls_range(max_finds=max_mongo_calls,
                                     min_finds=min_mongo_calls):
            _course_overview_1 = CourseOverview.get_from_id(course.id)

        # The second time we load a CourseOverview, it will be a cache hit, so
        # we expect no modulestore queries to be made.
        with check_mongo_calls(0):
            _course_overview_2 = CourseOverview.get_from_id(course.id)
Ejemplo n.º 12
0
    def test_user_randomly_assigned(self):
        # user was randomly assigned to one of the groups
        user_groups = _get_user_partition_groups(  # pylint: disable=protected-access
            self.course.id, [self.split_test_user_partition], self.user)
        self.assertEquals(len(user_groups), 1)

        # calling twice should result in the same block set
        with check_mongo_calls_range(min_finds=1):
            block_structure1 = get_course_blocks(
                self.user,
                self.course.location,
                transformers={self.transformer},
            )
        with check_mongo_calls(0):
            block_structure2 = get_course_blocks(
                self.user,
                self.course.location,
                transformers={self.transformer},
            )
        self.assertEqual(
            set(block_structure1.get_block_keys()),
            set(block_structure2.get_block_keys()),
        )
Ejemplo n.º 13
0
    def test_course_overview_caching(self, modulestore_type, min_mongo_calls, max_mongo_calls):
        """
        Tests that CourseOverview structures are actually getting cached.

        Arguments:
            modulestore_type (ModuleStoreEnum.Type): type of store to create the
                course in.
            min_mongo_calls (int): minimum number of MongoDB queries we expect
                to be made.
            max_mongo_calls (int): maximum number of MongoDB queries we expect
                to be made.
        """
        course = CourseFactory.create(default_store=modulestore_type)

        # The first time we load a CourseOverview, it will be a cache miss, so
        # we expect the modulestore to be queried.
        with check_mongo_calls_range(max_finds=max_mongo_calls, min_finds=min_mongo_calls):
            _course_overview_1 = CourseOverview.get_from_id(course.id)

        # The second time we load a CourseOverview, it will be a cache hit, so
        # we expect no modulestore queries to be made.
        with check_mongo_calls(0):
            _course_overview_2 = CourseOverview.get_from_id(course.id)
Ejemplo n.º 14
0
    def test_user_randomly_assigned(self):
        # user was randomly assigned to one of the groups
        user_groups = _get_user_partition_groups(  # pylint: disable=protected-access
            self.course.id, [self.split_test_user_partition], self.user
        )
        self.assertEquals(len(user_groups), 1)

        # calling twice should result in the same block set
        with check_mongo_calls_range(min_finds=1):
            block_structure1 = get_course_blocks(
                self.user,
                self.course.location,
                transformers={self.transformer},
            )
        with check_mongo_calls(0):
            block_structure2 = get_course_blocks(
                self.user,
                self.course.location,
                transformers={self.transformer},
            )
        self.assertEqual(
            set(block_structure1.get_block_keys()),
            set(block_structure2.get_block_keys()),
        )
 def assertMongoCallCount(self, calls):
     """
     Assert that mongodb is queried ``calls`` times in the surrounded
     context.
     """
     return check_mongo_calls_range(max_finds=calls)
Ejemplo n.º 16
0
    def assert_enrollment_status(
        self,
        course_id=None,
        username=None,
        expected_status=status.HTTP_200_OK,
        email_opt_in=None,
        as_server=False,
        mode=CourseMode.DEFAULT_MODE_SLUG,
        is_active=None,
        enrollment_attributes=None,
        min_mongo_calls=0,
        max_mongo_calls=0,
    ):
        """
        Enroll in the course and verify the response's status code. If the expected status is 200, also validates
        the response content.

        Returns
            Response
        """
        course_id = course_id or unicode(self.course.id)
        username = username or self.user.username

        data = {
            'mode': mode,
            'course_details': {
                'course_id': course_id
            },
            'user': username,
            'enrollment_attributes': enrollment_attributes
        }

        if is_active is not None:
            data['is_active'] = is_active

        if email_opt_in is not None:
            data['email_opt_in'] = email_opt_in

        extra = {}
        if as_server:
            extra['HTTP_X_EDX_API_KEY'] = self.API_KEY

        # Verify that the modulestore is queried as expected.
        with check_mongo_calls_range(min_finds=min_mongo_calls,
                                     max_finds=max_mongo_calls):
            with patch('enrollment.views.audit_log') as mock_audit_log:
                url = reverse('courseenrollments')
                response = self.client.post(url,
                                            json.dumps(data),
                                            content_type='application/json',
                                            **extra)
                self.assertEqual(response.status_code, expected_status)

                if expected_status == status.HTTP_200_OK:
                    data = json.loads(response.content)
                    self.assertEqual(course_id,
                                     data['course_details']['course_id'])

                    if mode is not None:
                        self.assertEqual(mode, data['mode'])

                    if is_active is not None:
                        self.assertEqual(is_active, data['is_active'])
                    else:
                        self.assertTrue(data['is_active'])

                    if as_server:
                        # Verify that an audit message was logged.
                        self.assertTrue(mock_audit_log.called)

                        # If multiple enrollment calls are made in the scope of a
                        # single test, we want to validate that audit messages are
                        # logged for each call.
                        mock_audit_log.reset_mock()

        return response
Ejemplo n.º 17
0
    def test_query_counts(self):
        self.add_credit_course(self.course.id)
        self.add_icrv_xblock()

        with check_mongo_calls_range(max_finds=7):
            on_course_publish(self.course.id)
 def test_query_counts_with_one_reverification_block(self):
     # One ICRV block created in the setup method
     # Additional call to load the ICRV block
     with check_mongo_calls_range(max_finds=5, max_sends=3):
         self._update_partitions(reload_items=False)
Ejemplo n.º 19
0
 def test_query_counts_with_one_reverification_block(self):
     # One ICRV block created in the setup method
     # Additional call to load the ICRV block
     with check_mongo_calls_range(max_finds=5, max_sends=3):
         self._update_partitions(reload_items=False)
 def test_query_counts_with_multiple_reverification_blocks(self):
     # Total of two ICRV blocks (one created in setup method)
     # Additional call to load each ICRV block
     ItemFactory.create(parent=self.verticals[3], category='edx-reverification-block')
     with check_mongo_calls_range(max_finds=6, max_sends=3):
         self._update_partitions(reload_items=False)
Ejemplo n.º 21
0
    def assert_enrollment_status(
            self,
            course_id=None,
            username=None,
            expected_status=status.HTTP_200_OK,
            email_opt_in=None,
            as_server=False,
            mode=CourseMode.DEFAULT_MODE_SLUG,
            is_active=None,
            enrollment_attributes=None,
            min_mongo_calls=0,
            max_mongo_calls=0,
            enterprise_course_consent=None,
    ):
        """
        Enroll in the course and verify the response's status code. If the expected status is 200, also validates
        the response content.

        Returns
            Response
        """
        course_id = course_id or unicode(self.course.id)
        username = username or self.user.username

        data = {
            'mode': mode,
            'course_details': {
                'course_id': course_id
            },
            'user': username,
            'enrollment_attributes': enrollment_attributes
        }

        if is_active is not None:
            data['is_active'] = is_active

        if email_opt_in is not None:
            data['email_opt_in'] = email_opt_in

        if enterprise_course_consent is not None:
            data['enterprise_course_consent'] = enterprise_course_consent

        extra = {}
        if as_server:
            extra['HTTP_X_EDX_API_KEY'] = self.API_KEY

        # Verify that the modulestore is queried as expected.
        with check_mongo_calls_range(min_finds=min_mongo_calls, max_finds=max_mongo_calls):
            with patch('enrollment.views.audit_log') as mock_audit_log:
                url = reverse('courseenrollments')
                response = self.client.post(url, json.dumps(data), content_type='application/json', **extra)
                self.assertEqual(response.status_code, expected_status)

                if expected_status == status.HTTP_200_OK:
                    data = json.loads(response.content)
                    self.assertEqual(course_id, data['course_details']['course_id'])

                    if mode is not None:
                        self.assertEqual(mode, data['mode'])

                    if is_active is not None:
                        self.assertEqual(is_active, data['is_active'])
                    else:
                        self.assertTrue(data['is_active'])

                    if as_server:
                        # Verify that an audit message was logged.
                        self.assertTrue(mock_audit_log.called)

                        # If multiple enrollment calls are made in the scope of a
                        # single test, we want to validate that audit messages are
                        # logged for each call.
                        mock_audit_log.reset_mock()

        return response
Ejemplo n.º 22
0
    def test_query_counts(self):
        self.add_credit_course(self.course.id)
        self.add_icrv_xblock()

        with check_mongo_calls_range(max_finds=11):
            on_course_publish(self.course.id)
 def assertMongoCallCount(self, calls):
     """
     Assert that mongodb is queried ``calls`` times in the surrounded
     context.
     """
     return check_mongo_calls_range(max_finds=calls)
Ejemplo n.º 24
0
    def assert_enrollment_status(
        self,
        course_id=None,
        username=None,
        expected_status=status.HTTP_200_OK,
        email_opt_in=None,
        as_server=False,
        mode=CourseMode.HONOR,
        is_active=None,
        enrollment_attributes=None,
        min_mongo_calls=0,
        max_mongo_calls=0,
    ):
        """
        Enroll in the course and verify the response's status code. If the expected status is 200, also validates
        the response content.

        Returns
            Response
        """
        course_id = course_id or unicode(self.course.id)
        username = username or self.user.username

        data = {
            "mode": mode,
            "course_details": {"course_id": course_id},
            "user": username,
            "enrollment_attributes": enrollment_attributes,
        }

        if is_active is not None:
            data["is_active"] = is_active

        if email_opt_in is not None:
            data["email_opt_in"] = email_opt_in

        extra = {}
        if as_server:
            extra["HTTP_X_EDX_API_KEY"] = self.API_KEY

        # Verify that the modulestore is queried as expected.
        with check_mongo_calls_range(min_finds=min_mongo_calls, max_finds=max_mongo_calls):
            with patch("enrollment.views.audit_log") as mock_audit_log:
                url = reverse("courseenrollments")
                response = self.client.post(url, json.dumps(data), content_type="application/json", **extra)
                self.assertEqual(response.status_code, expected_status)

                if expected_status == status.HTTP_200_OK:
                    data = json.loads(response.content)
                    self.assertEqual(course_id, data["course_details"]["course_id"])

                    if mode is not None:
                        self.assertEqual(mode, data["mode"])

                    if is_active is not None:
                        self.assertEqual(is_active, data["is_active"])
                    else:
                        self.assertTrue(data["is_active"])

                    if as_server:
                        # Verify that an audit message was logged.
                        self.assertTrue(mock_audit_log.called)

                        # If multiple enrollment calls are made in the scope of a
                        # single test, we want to validate that audit messages are
                        # logged for each call.
                        mock_audit_log.reset_mock()

        return response