def setUp(self): self.api_user = factories.UserFactory(username='******', id=1) self.user1 = factories.UserFactory(id=2, email='*****@*****.**') self.user2 = factories.UserFactory(id=3, email='*****@*****.**') self.course_id = COURSE_ID self.enterprise_customer = factories.EnterpriseCustomerFactory( name='Spaghetti Enterprise') self.identity_provider = FakerFactory.create().slug() # pylint: disable=no-member factories.EnterpriseCustomerIdentityProviderFactory( provider_id=self.identity_provider, enterprise_customer=self.enterprise_customer, ) self.enterprise_customer_user1 = factories.EnterpriseCustomerUserFactory( user_id=self.user1.id, enterprise_customer=self.enterprise_customer, ) self.enterprise_customer_user2 = factories.EnterpriseCustomerUserFactory( user_id=self.user2.id, enterprise_customer=self.enterprise_customer, ) self.enrollment = factories.EnterpriseCourseEnrollmentFactory( id=2, enterprise_customer_user=self.enterprise_customer_user1, course_id=self.course_id, ) self.enrollment = factories.EnterpriseCourseEnrollmentFactory( id=3, enterprise_customer_user=self.enterprise_customer_user2, course_id=self.course_id, ) self.consent1 = factories.DataSharingConsentFactory( username=self.user1.username, course_id=self.course_id, enterprise_customer=self.enterprise_customer, ) self.consent2 = factories.DataSharingConsentFactory( username=self.user2.username, course_id=self.course_id, enterprise_customer=self.enterprise_customer, ) self.degreed = factories.DegreedEnterpriseCustomerConfigurationFactory( enterprise_customer=self.enterprise_customer, key='key', secret='secret', degreed_company_id='Degreed Company', active=True, degreed_base_url='https://www.degreed.com/', ) self.degreed_global_configuration = factories.DegreedGlobalConfigurationFactory( oauth_api_path='oauth/token', ) self.sapsf = factories.SAPSuccessFactorsEnterpriseCustomerConfigurationFactory( enterprise_customer=self.enterprise_customer, sapsf_base_url='http://enterprise.successfactors.com/', key='key', secret='secret', active=True, ) self.sapsf_global_configuration = factories.SAPSuccessFactorsGlobalConfigurationFactory( ) super(TestTransmitLearnerData, self).setUp()
def test_get_learner_subsection_data_records(self): """ Test that the base learner subsection data exporter generates appropriate learner records from assessment grade data. """ enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) exporter = LearnerExporter('fake-user', self.config) assessment_grade_data = { 'subsection_1': { 'grade': 0.9, 'subsection_id': 'sub_1' }, 'subsection_2': { 'grade': 1.0, 'subsection_id': 'sub_2' } } learner_subsection_data_records = exporter.get_learner_assessment_data_records( enterprise_course_enrollment, assessment_grade_data ) for subsection_record in learner_subsection_data_records: if subsection_record.subsection_id == 'sub_1': assert subsection_record.grade == 0.9 else: assert subsection_record.grade == 1.0
def test_collect_learner_data_without_consent(self, mock_course_api, mock_grades_api, mock_enrollment_api): factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) self.data_sharing_consent.granted = False self.data_sharing_consent.save() # Return random course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='self' ) # Return enrollment mode data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert not learner_data assert mock_grades_api.call_count == 0 learner_assessment_data = list(self.exporter.bulk_assessment_level_export()) assert not learner_assessment_data assert mock_grades_api.call_count == 0
def test_get_learner_data_record(self, completed_date, is_passing): """ The base ``get_learner_data_record`` method returns a ``LearnerDataTransmissionAudit`` with appropriate values. """ enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) exporter = DegreedLearnerExporter('fake-user', self.config) learner_data_records = exporter.get_learner_data_records( enterprise_course_enrollment, completed_date=completed_date, is_passing=is_passing, ) assert len(learner_data_records) == 2 assert learner_data_records[0].course_id == self.course_key assert learner_data_records[1].course_id == self.course_id for learner_data_record in learner_data_records: assert learner_data_record.enterprise_course_enrollment_id == enterprise_course_enrollment.id assert learner_data_record.degreed_user_email == '*****@*****.**' assert learner_data_record.course_completed == (completed_date is not None and is_passing) assert learner_data_record.completed_timestamp == ( self.NOW.strftime('%F') if completed_date is not None else None)
def test_learner_data_self_paced_no_grades(self, mock_course_api, mock_grades_api, mock_enrollment_api): enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # Return instructor-paced course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='self', ) # Mock grades data not found mock_grades_api.return_value.get_course_grade.side_effect = HttpNotFoundError # Mock enrollment data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert len(learner_data) == 2 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert not report.course_completed assert report.completed_timestamp is None assert report.grade is None
def test_no_remote_id(self): """ If the TPA API Client returns no remote user ID, nothing is returned. """ self.tpa_client.return_value.get_remote_id.return_value = None exporter = DegreedLearnerExporter('fake-user', self.config) assert exporter.get_learner_data_records(factories.EnterpriseCourseEnrollmentFactory()) is None
def test_learner_data_instructor_paced_no_certificate_null_sso_id( self, mock_certificate_api, mock_course_api, mock_enrollment_api ): factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # No SSO user attached self.tpa_client.get_remote_id.return_value = None # Raise 404 - no certificate found mock_certificate_api.return_value.get_course_certificate.side_effect = HttpNotFoundError # Return instructor-paced course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='instructor', ) # Return enrollment mode data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert not learner_data
def test_get_learner_data_record(self, completed_date, is_passing): """ The base ``get_learner_data_record`` method returns a ``LearnerDataTransmissionAudit`` with appropriate values. """ enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) exporter = LearnerExporter('fake-user', self.config) learner_data_records = exporter.get_learner_data_records( enterprise_course_enrollment, completed_date=completed_date, grade='A+', is_passing=is_passing, ) learner_data_record = learner_data_records[0] assert learner_data_record.enterprise_course_enrollment_id == enterprise_course_enrollment.id assert learner_data_record.course_id == enterprise_course_enrollment.course_id assert learner_data_record.course_completed == (completed_date is not None and is_passing) assert learner_data_record.completed_timestamp == ( self.NOW_TIMESTAMP if completed_date is not None else None) assert learner_data_record.grade == 'A+'
def test_learner_data_instructor_paced_no_certificate( self, mock_course_catalog_api, mock_certificate_api, mock_course_api, mock_enrollment_api ): mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # Raise 404 - no certificate found mock_certificate_api.return_value.get_course_certificate.side_effect = HttpNotFoundError # Return instructor-paced course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='instructor', ) # Return enrollment mode data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert len(learner_data) == 2 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert not report.course_completed assert report.completed_timestamp is None assert report.grade == LearnerExporter.GRADE_INCOMPLETE
def _setup_enterprise_enrollment(self, user, course_id, course_key): """ Create enterprise enrollment for user in given course """ enterprise_customer_user = factories.EnterpriseCustomerUserFactory( user_id=user.id, enterprise_customer=self.enterprise_customer, ) factories.DataSharingConsentFactory( username=user.username, course_id=course_id, enterprise_customer=self.enterprise_customer, granted=True, ) enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=enterprise_customer_user, course_id=course_id, ) factories.CornerstoneLearnerDataTransmissionAuditFactory( user_id=user.id, session_token=self.session_token, callback_url=self.callback_url, subdomain=self.subdomain, course_id=course_key, user_guid=self.user_guid) return enterprise_course_enrollment
def test_collect_learner_data_no_course_details(self, mock_course_api): factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # Return no course details mock_course_api.return_value.get_course_details.return_value = None learner_data = list(self.exporter.export()) assert not learner_data
def test_learner_data_audit_data_reporting( self, enable_audit_enrollment, enable_reporting, mode, expected_data_len, mock_course_catalog_api, mock_course_api, mock_grades_api, mock_enrollment_api ): mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # Set the audit track data passback configuration self.enterprise_customer.enable_audit_enrollment = enable_audit_enrollment self.enterprise_customer.enable_audit_data_reporting = enable_reporting self.enterprise_customer.save() # Use self-paced course to get grades data mock_course_api.return_value.get_course_details.return_value = dict( pacing='self', course_id=self.course_id, ) # Mock grades data mock_grades_api.return_value.get_course_grade.return_value = dict( passed=True, ) # Mock enrollment data, in particular the enrollment mode mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode=mode ) # Collect the learner data with freeze_time(self.NOW): learner_data = list(self.exporter.export()) assert len(learner_data) == expected_data_len if expected_data_len == 2: assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert report.course_completed assert report.grade == LearnerExporter.GRADE_PASSING
def test_get_learner_data_record_not_exist(self): """ If learner data is not already exist, nothing is returned. """ exporter = CornerstoneLearnerExporter('fake-user', self.config) enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=factories.EnterpriseCustomerUserFactory( user_id=self.other_user.id, enterprise_customer=self.enterprise_customer, ), course_id=self.course_id, ) assert exporter.get_learner_data_records(enterprise_course_enrollment) is None
def test_learner_data_self_paced_course( self, passing, end_date, expected_completion, expected_grade, course_enrollment_mode, mock_course_catalog_api, mock_course_api, mock_grades_api, mock_enrollment_api ): enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key # Mock self-paced course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='self', end=end_date.isoformat() if end_date else None, ) # Mock grades data mock_grades_api.return_value.get_course_grade.return_value = dict( passed=passing, ) # Mock enrollment data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode=course_enrollment_mode, ) # Collect the learner data, with time set to NOW with freeze_time(self.NOW): learner_data = list(self.exporter.export()) assert len(learner_data) == 2 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert report.course_completed == (passing and expected_completion is not None) assert report.completed_timestamp == expected_completion assert report.grade == expected_grade
def setUp(self): super().setUp() self.global_config = factories.SAPSuccessFactorsGlobalConfigurationFactory( ) self.enterprise_customer = factories.EnterpriseCustomerFactory() self.enterprise_customer_user = factories.EnterpriseCustomerUserFactory( enterprise_customer=self.enterprise_customer) self.enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( id=5, enterprise_customer_user=self.enterprise_customer_user) self.enterprise_config = factories.SAPSuccessFactorsEnterpriseCustomerConfigurationFactory( enterprise_customer=self.enterprise_customer, key="client_id", sapsf_base_url="http://test.successfactors.com/", sapsf_company_id="company_id", sapsf_user_id="user_id", secret="client_secret") self.payloads = [ SapSuccessFactorsLearnerDataTransmissionAudit( enterprise_course_enrollment_id=self. enterprise_course_enrollment.id, sapsf_user_id='sap_user', course_id='course-v1:edX+DemoX+DemoCourse', course_completed=True, completed_timestamp=1486855998, instructor_name='Professor Professorson', grade='Passing even more', error_message='', ) ] self.exporter = lambda payloads=self.payloads: mock.MagicMock( export=mock.MagicMock(return_value=iter(payloads))) # Mocks get_oauth_access_token_mock = mock.patch( 'integrated_channels.sap_success_factors.client.SAPSuccessFactorsAPIClient.get_oauth_access_token' ) self.get_oauth_access_token_mock = get_oauth_access_token_mock.start() self.get_oauth_access_token_mock.return_value = "token", datetime.datetime.utcnow( ) self.addCleanup(get_oauth_access_token_mock.stop) create_course_completion_mock = mock.patch( 'integrated_channels.sap_success_factors.client.SAPSuccessFactorsAPIClient.create_course_completion' ) self.create_course_completion_mock = create_course_completion_mock.start( ) self.addCleanup(create_course_completion_mock.stop)
def test_learner_data_instructor_paced_with_certificate( self, mock_course_catalog_api, mock_certificate_api, mock_course_api, mock_enrollment_api ): mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) # Return a mock certificate certificate = dict( username=self.user, course_id=self.course_id, certificate_type='professional', created_date=self.NOW.isoformat(), status="downloadable", is_passing=True, grade='A-', ) mock_certificate_api.return_value.get_course_certificate.return_value = certificate # Return instructor-paced course details mock_course_api.return_value.get_course_details.return_value = dict( pacing='instructor', ) # Mock enrollment data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert len(learner_data) == 2 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert report.course_completed assert report.completed_timestamp == self.NOW_TIMESTAMP assert report.grade == LearnerExporter.GRADE_PASSING
def setUp(self): super().setUp() self.enterprise_customer = factories.EnterpriseCustomerFactory() self.enterprise_customer_user = factories.EnterpriseCustomerUserFactory( enterprise_customer=self.enterprise_customer, ) self.enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( id=5, enterprise_customer_user=self.enterprise_customer_user, ) self.enterprise_config = factories.MoodleEnterpriseCustomerConfigurationFactory( enterprise_customer=self.enterprise_customer, moodle_base_url='foobar', service_short_name='shortname', category_id=1, username='******', password='******', token='token', ) self.payload = MoodleLearnerDataTransmissionAudit( moodle_user_email=self.enterprise_customer.contact_email, enterprise_course_enrollment_id=self.enterprise_course_enrollment. id, course_id='course-v1:edX+DemoX+DemoCourse', course_completed=True, completed_timestamp=1486855998, total_hours=1.0, grade=.9, ) self.exporter = lambda payloads=self.payload: mock.MagicMock( export=mock.MagicMock(return_value=iter(payloads))) # Mocks create_course_completion_mock = mock.patch( 'integrated_channels.moodle.client.MoodleAPIClient.create_course_completion' ) self.create_course_completion_mock = create_course_completion_mock.start( ) self.addCleanup(create_course_completion_mock.stop) self.create_course_completion_mock = create_course_completion_mock.start( ) self.addCleanup(create_course_completion_mock.stop)
def setUp(self): super(TestBlackboardLearnerDataTransmitter, self).setUp() self.enterprise_customer = factories.EnterpriseCustomerFactory() self.enterprise_customer_user = factories.EnterpriseCustomerUserFactory( enterprise_customer=self.enterprise_customer, ) self.enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( id=5, enterprise_customer_user=self.enterprise_customer_user, ) self.enterprise_config = factories.BlackboardEnterpriseCustomerConfigurationFactory( enterprise_customer=self.enterprise_customer, blackboard_base_url='foobar', client_id='client_id', client_secret='client_secret', refresh_token='token', ) self.payload = BlackboardLearnerDataTransmissionAudit( blackboard_user_email=self.enterprise_customer.contact_email, enterprise_course_enrollment_id=self.enterprise_course_enrollment. id, course_id='course-v1:edX+DemoX+DemoCourse', course_completed=True, completed_timestamp=1486855998, total_hours=1.0, grade=.9, ) self.exporter = lambda payloads=self.payload: mock.MagicMock( export=mock.MagicMock(return_value=iter(payloads))) # Mocks create_course_completion_mock = mock.patch( 'integrated_channels.blackboard.client.BlackboardAPIClient.create_course_completion' ) self.create_course_completion_mock = create_course_completion_mock.start( ) self.addCleanup(create_course_completion_mock.stop) self.create_course_completion_mock = create_course_completion_mock.start( ) self.addCleanup(create_course_completion_mock.stop)
def test_learner_data_self_paced_no_grades( self, mock_course_catalog_api, mock_course_api, mock_grades_api, mock_enrollment_api, ): enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key # Return self-paced course details mock_course_api.return_value.get_course_details.return_value = { 'pacing': 'self', } # Mock grades data not found mock_grades_api.return_value.get_course_grade.side_effect = HttpNotFoundError( 'No grade record found for course={}, username={}'.format(self.course_id, self.user.username) ) # Mock enrollment data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) learner_data = list(self.exporter.export()) assert len(learner_data) == 2 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report in learner_data: assert report.enterprise_course_enrollment_id == enrollment.id assert not report.course_completed assert report.completed_timestamp is None assert report.grade is None
def test_learner_exporter_with_skip_transmitted(self, mock_course_api, mock_grades_api, mock_enrollment_api): enterprise_course_enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) transmission_audit = LearnerDataTransmissionAudit( enterprise_course_enrollment_id=enterprise_course_enrollment.id, course_id=self.course_id, course_completed=True, completed_timestamp=1568877047181, grade='Pass', ) transmission_audit.save() learner_data = list( self.exporter.export( TransmissionAudit=LearnerDataTransmissionAudit)) assert not learner_data assert mock_enrollment_api.call_count == 0 assert mock_course_api.call_count == 0 assert mock_grades_api.call_count == 0
def test_learner_assessment_data_export( self, mock_course_catalog_api, mock_grades_api, mock_enrollment_api ): enrollment = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode='verified', ) # Mock grades data assessment_grade_data = [dict( attempted=True, subsection_name='subsection_1', category='subsection_category', percent=1.0, label='subsection_label', score_earned=10, score_possible=10, module_id='subsection_id_1' )] mock_grades_api.return_value.get_course_assessment_grades.return_value = assessment_grade_data learner_data = list(self.exporter.bulk_assessment_level_export()) assert learner_data[0].course_id == self.course_id assert learner_data[0].enterprise_course_enrollment_id == enrollment.id assert learner_data[0].grade == 1.0 assert learner_data[0].subsection_id == 'subsection_id_1'
def test_learner_data_multiple_courses( self, pacing, grade, mock_course_catalog_api, mock_course_api, mock_grades_api, mock_certificate_api, mock_enrollment_api ): mock_course_catalog_api.return_value.get_course_id.return_value = self.course_key enrollment1 = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=self.course_id, ) course_id2 = 'course-v1:edX+DemoX+DemoCourse2' enrollment2 = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=self.enterprise_customer_user, course_id=course_id2, ) factories.DataSharingConsentFactory( username=self.enterprise_customer_user.username, course_id=course_id2, enterprise_customer=self.enterprise_customer, granted=True ) enrollment3 = factories.EnterpriseCourseEnrollmentFactory( enterprise_customer_user=factories.EnterpriseCustomerUserFactory( user_id=factories.UserFactory(username='******', id=2).id, enterprise_customer=self.enterprise_customer, ), course_id=self.course_id, ) factories.DataSharingConsentFactory( username='******', course_id=self.course_id, enterprise_customer=self.enterprise_customer, granted=True ) def get_course_details(course_id): """ Mock course details - set course_id to match input """ return dict( pacing=pacing, course_id=course_id ) mock_course_api.return_value.get_course_details.side_effect = get_course_details def get_course_certificate(course_id, username): """ Mock certificate data - return depending on course_id """ if '2' in course_id: return dict( username=username, is_passing=True, grade=grade, ) raise HttpNotFoundError mock_certificate_api.return_value.get_course_certificate.side_effect = get_course_certificate def get_course_grade(course_id, username): """ Mock grades data - set passed depending on course_id """ return dict( passed='2' in course_id, course_key=course_id, username=username, ) mock_grades_api.return_value.get_course_grade.side_effect = get_course_grade # Mock enrollment data mock_enrollment_api.return_value.get_course_enrollment.return_value = dict( mode="verified" ) # Collect the learner data, with time set to NOW with freeze_time(self.NOW): learner_data = list(self.exporter.export()) assert len(learner_data) == 6 assert learner_data[0].course_id == self.course_key assert learner_data[1].course_id == self.course_id for report1 in learner_data[0:1]: assert report1.enterprise_course_enrollment_id == enrollment1.id assert not report1.course_completed assert report1.completed_timestamp is None assert report1.grade == LearnerExporter.GRADE_INCOMPLETE assert learner_data[2].course_id == self.course_key assert learner_data[3].course_id == self.course_id for report2 in learner_data[2:3]: assert report2.enterprise_course_enrollment_id == enrollment3.id assert not report2.course_completed assert report2.completed_timestamp is None assert report2.grade == LearnerExporter.GRADE_INCOMPLETE assert learner_data[4].course_id == self.course_key assert learner_data[5].course_id == course_id2 for report3 in learner_data[4:5]: assert report3.enterprise_course_enrollment_id == enrollment2.id # assert report3.course_id == course_id2 assert report3.course_completed assert report3.completed_timestamp == self.NOW_TIMESTAMP assert report3.grade == grade