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)
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)
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)
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)
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)
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)
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)
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")))
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")))
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)
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 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)
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
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)
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
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 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