def test_course_progress(self, mock_get_programs): """ Verify that the progress meter can represent progress in terms of serialized courses. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[] ) ] self.assertEqual(meter.progress(count_only=False), expected)
def test_no_id_professional_in_progress(self, mock_get_programs): """ Verify that the progress meter treats no-id-professional enrollments as professional. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key, type=CourseMode.PROFESSIONAL), ]), ] ) ] mock_get_programs.return_value = data CourseEnrollmentFactory( user=self.user, course_id=course_run_key, mode=CourseMode.NO_ID_PROFESSIONAL_MODE ) meter = ProgramProgressMeter(self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[] ) ] self.assertEqual(meter.progress(count_only=False), expected)
def test_handle(self, commit, mock_task, mock_get_programs): """ Verify that relevant tasks are only enqueued when the commit option is passed. """ data = [ ProgramFactory(courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=self.course_run_key), ]), ]), ] mock_get_programs.return_value = data GeneratedCertificateFactory( user=self.alice, course_id=self.course_run_key, mode=MODES.verified, status=CertificateStatuses.downloadable, ) GeneratedCertificateFactory( user=self.bob, course_id=self.alternate_course_run_key, mode=MODES.verified, status=CertificateStatuses.downloadable, ) call_command('backpopulate_program_credentials', commit=commit) if commit: mock_task.assert_called_once_with(self.alice.username) else: mock_task.assert_not_called()
def test_single_program_engagement(self, mock_get_programs): """ Verify that correct program is returned when the user is enrolled in a course run appearing in one program. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ), ProgramFactory(), ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.user) self._attach_detail_url(data) program = data[0] self.assertEqual(meter.engaged_programs, [program]) self._assert_progress( meter, ProgressFactory(uuid=program['uuid'], in_progress=1) ) self.assertEqual(meter.completed_programs, [])
def setUpClass(cls): super().setUpClass() cls.user = UserFactory() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=str(modulestore_course.id)) course = CourseFactory(course_runs=[course_run]) enterprise_customer = EnterpriseCustomerFactory( uuid=cls.enterprise_uuid) enterprise_customer_user = EnterpriseCustomerUserFactory( user_id=cls.user.id, enterprise_customer=enterprise_customer) CourseEnrollmentFactory(is_active=True, course_id=modulestore_course.id, user=cls.user) EnterpriseCourseEnrollmentFactory( course_id=modulestore_course.id, enterprise_customer_user=enterprise_customer_user) cls.program = ProgramFactory( uuid=cls.program_uuid, courses=[course], title='Journey to cooking', type='MicroMasters', authoring_organizations=[{ 'key': 'MAX' }], ) cls.site = SiteFactory(domain='test.localhost')
def test_handle_mode_slugs(self, mock_task, mock_get_programs): """ Verify that course run types are taken into account when identifying qualifying course run certificates. """ data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=self.course_run_key, type='honor'), ]), ] ), ] mock_get_programs.return_value = data GeneratedCertificateFactory( user=self.alice, course_id=self.course_run_key, mode=MODES.honor, status=CertificateStatuses.downloadable, ) GeneratedCertificateFactory( user=self.bob, course_id=self.course_run_key, mode=MODES.verified, status=CertificateStatuses.downloadable, ) call_command('backpopulate_program_credentials', commit=True) mock_task.assert_called_once_with(self.alice.username)
def setUp(self): """ Test case setup """ super().setUp() self.client = Client() user = AdminFactory() self.view_url = reverse('admin:enterprise_override_attributes') self.client.login(username=user.username, password=TEST_PASSWORD) self.users = [] for _ in range(3): self.users.append(UserFactory()) self.course = CourseRunFactory() self.course_id = self.course.get('key') # lint-amnesty, pylint: disable=no-member self.csv_data = [ [self.users[0].id, self.course_id, 'OP_4321'], [self.users[1].id, self.course_id, 'OP_8765'], [self.users[2].id, self.course_id, 'OP_2109'], ] self.csv_data_for_existing_attributes = [ [self.users[0].id, self.course_id, 'OP_1234'], [self.users[1].id, self.course_id, 'OP_5678'], [self.users[2].id, self.course_id, 'OP_9012'], ] for user in self.users: CourseEnrollmentFactory( course_id=self.course_id, user=user )
def setUpClass(cls): super().setUpClass() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=str(modulestore_course.id)) course = CourseFactory(course_runs=[course_run]) cls.program = ProgramFactory(uuid=cls.program_uuid, courses=[course])
def test_handle_professional(self, mock_task, mock_get_programs): """ Verify the task can handle both professional and no-id-professional modes. """ mock_get_programs.return_value = [ ProgramFactory(courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=self.course_run_key, type='professional'), ]), ]), ] GeneratedCertificateFactory( user=self.alice, course_id=self.course_run_key, mode=CourseMode.PROFESSIONAL, status=CertificateStatuses.downloadable, ) GeneratedCertificateFactory( user=self.bob, course_id=self.course_run_key, mode=CourseMode.NO_ID_PROFESSIONAL_MODE, status=CertificateStatuses.downloadable, ) call_command('backpopulate_program_credentials', commit=True) # The task should be called for both users since professional and no-id-professional are equivalent. mock_task.assert_has_calls( [mock.call(self.alice.username), mock.call(self.bob.username)], any_order=True)
def create_program(self): """DRY helper for creating test program data.""" course_run = CourseRunFactory(key=self.course_id) course = CourseFactory(course_runs=[course_run]) program_type = ProgramTypeFactory() return ProgramFactory(courses=[course], type=program_type['name'])
def setUpClass(cls): super(TestProgramDetails, cls).setUpClass() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=unicode(modulestore_course.id)) # pylint: disable=no-member course = CourseFactory(course_runs=[course_run]) cls.data = ProgramFactory(uuid=cls.program_uuid, courses=[course])
def setUp(self): super(TestSyncCourseRunsCommand, self).setUp() # create mongo course self.course = CourseFactory.create() # load this course into course overview CourseOverview.get_from_id(self.course.id) # create a catalog course run with the same course id. self.catalog_course_run = CourseRunFactory( key=unicode(self.course.id), marketing_url='test_marketing_url')
def test_shared_enrollment_engagement(self, mock_get_programs): """ Verify that correct programs are returned when the user is enrolled in a single course run appearing in multiple programs. """ shared_course_run_key, solo_course_run_key = (generate_course_run_key() for __ in range(2)) batch = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=shared_course_run_key), ]), ] ) for __ in range(2) ] joint_programs = sorted(batch, key=lambda program: program['title']) data = joint_programs + [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=solo_course_run_key), ]), ] ), ProgramFactory(), ] mock_get_programs.return_value = data # Enrollment for the shared course run created last (most recently). self._create_enrollments(solo_course_run_key, shared_course_run_key) meter = ProgramProgressMeter(self.user) self._attach_detail_url(data) programs = data[:3] self.assertEqual(meter.engaged_programs, programs) self._assert_progress( meter, *(ProgressFactory(uuid=program['uuid'], in_progress=1) for program in programs) ) self.assertEqual(meter.completed_programs, [])
def test_mutiple_program_engagement(self, mock_get_programs): """ Verify that correct programs are returned in the correct order when the user is enrolled in course runs appearing in programs. """ newer_course_run_key, older_course_run_key = (generate_course_run_key() for __ in range(2)) data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=newer_course_run_key), ]), ] ), ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=older_course_run_key), ]), ] ), ProgramFactory(), ] mock_get_programs.return_value = data # The creation time of the enrollments matters to the test. We want # the first_course_run_key to represent the newest enrollment. self._create_enrollments(older_course_run_key, newer_course_run_key) meter = ProgramProgressMeter(self.site, self.user) self._attach_detail_url(data) programs = data[:2] self.assertEqual(meter.engaged_programs, programs) grades = { newer_course_run_key: 0.0, older_course_run_key: 0.0, } self._assert_progress( meter, *(ProgressFactory(uuid=program['uuid'], in_progress=1, grades=grades) for program in programs) ) self.assertEqual(meter.completed_programs, [])
def test_program_uuid_args(self, mock_get_programs, mock_task): course_1_id = 'course-v1:edX+Test+1' course_2_id = 'course-v1:edX+Test+2' program = ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_1_id), CourseRunFactory(key=course_2_id) ]) ], curricula=[], ) self.expected_options['program_uuids'] = [program['uuid']] mock_get_programs.return_value = [program] call_command(Command(), '--program_uuids', program['uuid']) assert mock_task.called assert mock_task.call_args[0][0] == self.expected_options assert mock_task.call_args[0][1].sort() == [course_1_id, course_2_id].sort()
def test_get_course_runs(self, mock_get_edx_api_data): """ Test retrieval of course runs. """ catalog_course_runs = [CourseRunFactory() for __ in xrange(10)] mock_get_edx_api_data.return_value = catalog_course_runs data = get_course_runs() self.assertTrue(mock_get_edx_api_data.called) self.assert_contract(mock_get_edx_api_data.call_args) self.assertEqual(data, catalog_course_runs)
def setUp(self): super().setUp() self.url = reverse('dashboard') self.create_programs_config() self.client.login(username=self.user.username, password=self.password) course_run = CourseRunFactory(key=str(self.course.id)) # pylint: disable=no-member course = CatalogCourseFactory(course_runs=[course_run]) self.programs = [ProgramFactory(courses=[course]) for __ in range(2)]
def setUpClass(cls): super(TestProgramListing, cls).setUpClass() cls.course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=six.text_type(cls.course.id)) course = CourseFactory(course_runs=[course_run]) cls.first_program = ProgramFactory(courses=[course]) cls.second_program = ProgramFactory(courses=[course]) cls.data = sorted([cls.first_program, cls.second_program], key=cls.program_sort_key)
def setUpClass(cls): super().setUpClass() cls.course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=str(cls.course.id)) # lint-amnesty, pylint: disable=no-member course = CourseFactory(course_runs=[course_run]) cls.first_program = ProgramFactory(courses=[course]) cls.second_program = ProgramFactory(courses=[course]) cls.data = sorted([cls.first_program, cls.second_program], key=cls.program_sort_key)
def setUp(self): super().setUp() # create mongo course self.course = CourseFactory.create() # load this course into course overview self.course_overview = CourseOverview.get_from_id(self.course.id) # create a catalog course run with the same course id. self.catalog_course_run = CourseRunFactory( key=str(self.course.id), marketing_url='test_marketing_url', eligible_for_financial_aid=False)
def setUp(self): super(TestProgramDataExtender, self).setUp() self.course = ModuleStoreCourseFactory() self.course.start = datetime.datetime.now(utc) - datetime.timedelta(days=1) self.course.end = datetime.datetime.now(utc) + datetime.timedelta(days=1) self.course = self.update_course(self.course, self.user.id) self.course_run = CourseRunFactory(key=unicode(self.course.id)) self.catalog_course = CourseFactory(course_runs=[self.course_run]) self.program = ProgramFactory(courses=[self.catalog_course])
def setUp(self): super(TestSyncCourseRunsCommand, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments # create mongo course self.course = CourseFactory.create() # load this course into course overview self.course_overview = CourseOverview.get_from_id(self.course.id) # create a catalog course run with the same course id. self.catalog_course_run = CourseRunFactory( key=six.text_type(self.course.id), marketing_url='test_marketing_url', eligible_for_financial_aid=False)
def test_multiple_published_course_runs(self): """ Learner should not be eligible for one click purchase if: - program has a course with more than one published course run """ course_run_1 = CourseRunFactory( key=str(ModuleStoreCourseFactory().id), status='published' ) course_run_2 = CourseRunFactory( key=str(ModuleStoreCourseFactory().id), status='published' ) course = CourseFactory(course_runs=[course_run_1, course_run_2]) program = ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory( key=str(ModuleStoreCourseFactory().id), status='published' ) ]), course, CourseFactory(course_runs=[ CourseRunFactory( key=str(ModuleStoreCourseFactory().id), status='published' ) ]) ], is_program_eligible_for_one_click_purchase=True, applicable_seat_types=['verified'] ) data = ProgramDataExtender(program, self.user).extend() self.assertFalse(data['is_learner_eligible_for_one_click_purchase']) course_run_2['status'] = 'unpublished' data = ProgramDataExtender(program, self.user).extend() self.assertTrue(data['is_learner_eligible_for_one_click_purchase'])
def setUpClass(cls): super(TestProgramDetails, cls).setUpClass() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=six.text_type(modulestore_course.id)) course = CourseFactory(course_runs=[course_run]) cls.program_data = ProgramFactory(uuid=cls.program_uuid, courses=[course]) cls.pathway_data = PathwayFactory() cls.program_data['pathway_ids'] = [cls.pathway_data['id']] cls.pathway_data['program_uuids'] = [cls.program_data['uuid']] del cls.pathway_data['programs']
def setUpClass(cls): super(TestProgramDetails, cls).setUpClass() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=unicode(modulestore_course.id)) # pylint: disable=no-member course = CourseFactory(course_runs=[course_run]) cls.program_data = ProgramFactory(uuid=cls.program_uuid, courses=[course]) cls.pathway_data = CreditPathwayFactory() cls.program_data['pathway_ids'] = [cls.pathway_data['id']] cls.pathway_data['program_uuids'] = [cls.program_data['uuid']] del cls.pathway_data['programs']
def setUpClass(cls): super().setUpClass() modulestore_course = ModuleStoreCourseFactory() course_run = CourseRunFactory(key=str(modulestore_course.id)) # lint-amnesty, pylint: disable=no-member course = CourseFactory(course_runs=[course_run]) cls.program_data = ProgramFactory(uuid=cls.program_uuid, courses=[course]) cls.pathway_data = PathwayFactory() cls.program_data['pathway_ids'] = [cls.pathway_data['id']] cls.pathway_data['program_uuids'] = [cls.program_data['uuid']] del cls.pathway_data['programs'] # lint-amnesty, pylint: disable=unsupported-delete-operation
def test_unrelated_program_not_listed(self, mock_get_programs): """Verify that unrelated programs don't appear in the listing.""" nonexistent_course_run_id = generate_course_run_key() course_run = CourseRunFactory(key=nonexistent_course_run_id) course = CatalogCourseFactory(course_runs=[course_run]) unrelated_program = ProgramFactory(courses=[course]) mock_get_programs.return_value = self.programs + [unrelated_program] response = self.client.get(self.url) self.assert_related_programs(response) self.assertNotContains(response, unrelated_program['title'])
def test_get_course_run_details(self, mock_get_course_run_details): """ Test for Python API `get_course_run_details` function. """ course_run = CourseRunFactory() mock_get_course_run_details.return_value = { 'title': course_run['title'], } results = get_course_run_details(course_run['key'], ['title']) assert results['title'] == course_run['title']
def test_course_pricing_when_all_course_runs_have_no_seats(self): # Create three seatless course runs and add them to the program course_runs = [] for __ in range(3): course = ModuleStoreCourseFactory() course = self.update_course(course, self.user.id) course_runs.append(CourseRunFactory(key=unicode(course.id), seats=[])) program = ProgramFactory(courses=[CourseFactory(course_runs=course_runs)]) data = ProgramMarketingDataExtender(program, self.user).extend() self.assertEqual(data['number_of_courses'], len(program['courses'])) self.assertEqual(data['full_program_price'], 0.0) self.assertEqual(data['avg_price_per_course'], 0.0)
def test_get_course_run_details(self, mock_get_edx_api_data): """ Test retrieval of details about a specific course run """ course_run = CourseRunFactory() course_run_details = { 'content_language': course_run['content_language'], 'weeks_to_complete': course_run['weeks_to_complete'], 'max_effort': course_run['max_effort'] } mock_get_edx_api_data.return_value = course_run_details data = get_course_run_details(course_run['key'], ['content_language', 'weeks_to_complete', 'max_effort']) self.assertTrue(mock_get_edx_api_data.called) self.assertEqual(data, course_run_details)