def setUpClass(cls): super().setUpClass() cls.store = modulestore() cls.course = CourseFactory.create( start=datetime(2020, 1, 1), end=datetime(2028, 1, 1), enrollment_start=datetime(2020, 1, 1), enrollment_end=datetime(2028, 1, 1), emit_signals=True, modulestore=cls.store, ) chapter = ItemFactory(parent=cls.course, category='chapter') ItemFactory(parent=chapter, category='sequential') CourseModeFactory(course_id=cls.course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=cls.course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=datetime(2028, 1, 1)) VerificationDeadline.objects.create(course_key=cls.course.id, deadline=datetime(2028, 1, 1)) cls.user = UserFactory(username='******', email='*****@*****.**', password='******', is_staff=False) CourseOverviewFactory.create(run='1T2020')
def create_self_paced_course_run(days_till_start=1, org_id=None): """ Create a new course run and course modes. All date-related arguments are relative to the current date-time (now) unless otherwise specified. Both audit and verified `CourseMode` objects will be created for the course run. Arguments: days_till_start (int): Number of days until the course starts. org_id (string): String org id to assign the course to (default: None; use CourseFactory default) """ now = datetime.now(utc) course = CourseFactory.create(start=now + timedelta(days=days_till_start), self_paced=True, org=org_id if org_id else 'TestedX') CourseModeFactory( course_id=course.id, mode_slug=CourseMode.AUDIT ) CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=now + timedelta(days=100) ) return course
def setUp(self): super(PermissionTests, self).setUp() self.user = UserFactory() self.course_id = CourseLocator('MITx', '000', 'Perm_course') CourseModeFactory(mode_slug='verified', course_id=self.course_id) CourseModeFactory(mode_slug='masters', course_id=self.course_id)
def test_suggested_prices(self, price_list): # Create the course modes for mode in ('audit', 'honor'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory( mode_slug='verified', course_id=self.course.id, suggested_prices=price_list ) # Enroll the user in the test course to emulate # automatic enrollment CourseEnrollmentFactory( is_active=True, course_id=self.course.id, user=self.user ) # Verify that the prices render correctly response = self.client.get( reverse('course_modes_choose', args=[unicode(self.course.id)]), follow=False, ) self.assertEquals(response.status_code, 200)
def setUp(self): super(EntitlementEnrollmentViewSetTest, self).setUp() self.user = UserFactory() UserFactory(username=settings.ECOMMERCE_SERVICE_WORKER_USERNAME, is_staff=True) self.client.login(username=self.user.username, password=TEST_PASSWORD) self.course = CourseFactory.create(org='edX', number='DemoX', display_name='Demo_Course') self.course2 = CourseFactory.create(org='edX', number='DemoX2', display_name='Demo_Course 2') self.course_mode = CourseModeFactory( course_id=self.course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1) ) self.course_mode = CourseModeFactory( course_id=self.course2.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1) ) self.return_values = [ {'key': str(self.course.id)}, {'key': str(self.course2.id)} ]
def test_bulk_convert_with_org(self, from_mode, to_mode, mock_tracker): """Verify that enrollments are changed correctly when org was given.""" self._enroll_users(self.course, self.users, from_mode) CourseModeFactory(course_id=self.course.id, mode_slug=to_mode) # Create a second course under the same org course_2 = CourseFactory.create(org=self.org) CourseModeFactory(course_id=course_2.id, mode_slug=to_mode) CourseOverview.load_from_module_store(course_2.id) self._enroll_users(course_2, self.users, from_mode) # Verify that no users are in the `to` mode yet. self.assertEqual(len(CourseEnrollment.objects.filter(mode=to_mode, course_id=self.course.id)), 0) self.assertEqual(len(CourseEnrollment.objects.filter(mode=to_mode, course_id=course_2.id)), 0) args = '--org {org} --from_mode {from_mode} --to_mode {to_mode} --commit'.format( org=self.org, from_mode=from_mode, to_mode=to_mode ) call_command( 'bulk_change_enrollment', *args.split(' ') ) # Verify that all users have been moved -- if not, this will # raise CourseEnrollment.DoesNotExist for user in self.users: for course in [self.course, course_2]: CourseEnrollment.objects.get(mode=to_mode, course_id=course.id, user=user) self._assert_mode_changed(mock_tracker, course, user, to_mode)
def setUp(self): super().setUp() self.course = CourseFactory.create( start=datetime(2020, 1, 1), end=datetime(2028, 1, 1), enrollment_start=datetime(2020, 1, 1), enrollment_end=datetime(2028, 1, 1), emit_signals=True, modulestore=self.store, ) chapter = ItemFactory(parent=self.course, category='chapter') ItemFactory(parent=chapter, category='sequential') CourseModeFactory(course_id=self.course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=self.course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=datetime(2028, 1, 1)) VerificationDeadline.objects.create(course_key=self.course.id, deadline=datetime(2028, 1, 1)) CourseOverviewFactory.create(run='1T2020') self.staff_user = self.user self.user, password = self.create_non_staff_user() self.client.login(username=self.user.username, password=password)
def setUp(self): super(TrackSelectionEmbargoTest, self).setUp('embargo') # Create a course and course modes self.course = CourseFactory.create() CourseModeFactory(mode_slug='honor', course_id=self.course.id) CourseModeFactory(mode_slug='verified', course_id=self.course.id, min_price=10) # Create a user and log in self.user = UserFactory.create(username="******", email="*****@*****.**", password="******") self.client.login(username=self.user.username, password="******") # Construct the URL for the track selection page self.url = reverse('course_modes_choose', args=[unicode(self.course.id)])
def _create_course_run(self_paced=True, start_day_offset=-1): """ Create a new course run and course modes. Both audit and verified `CourseMode` objects will be created for the course run. """ now = datetime.datetime.now(utc) start = now + datetime.timedelta(days=start_day_offset) course = CourseFactory.create(start=start, self_paced=self_paced) CourseModeFactory(course_id=course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=now + datetime.timedelta(days=100)) return course
def setUp(self): super(TestReverificationService, self).setUp() self.user = UserFactory.create(username="******", password="******") self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_id = self.course.id CourseModeFactory( mode_slug="verified", course_id=self.course_id, min_price=100, ) self.course_key = CourseKey.from_string(unicode(self.course_id)) self.item = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section') self.final_checkpoint_location = u'i4x://{org}/{course}/edx-reverification-block/final_uuid'.format( org=self.course_id.org, course=self.course_id.course) # Enroll in a verified mode self.enrollment = CourseEnrollment.enroll(self.user, self.course_id, mode=CourseMode.VERIFIED)
def test_bulk_convert(self, from_mode, to_mode, mock_tracker): """Verify that enrollments are changed correctly.""" self._enroll_users(self.course, self.users, from_mode) CourseModeFactory(course_id=self.course.id, mode_slug=to_mode) # Verify that no users are in the `from` mode yet. self.assertEqual( len( CourseEnrollment.objects.filter(mode=to_mode, course_id=self.course.id)), 0) call_command( 'bulk_change_enrollment', course=unicode(self.course.id), from_mode=from_mode, to_mode=to_mode, commit=True, ) # Verify that all users have been moved -- if not, this will # raise CourseEnrollment.DoesNotExist for user in self.users: CourseEnrollment.objects.get(mode=to_mode, course_id=self.course.id, user=user) self._assert_mode_changed(mock_tracker, self.course, user, to_mode)
def test_successful_default_enrollment(self): # Create the course modes for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Enroll the user in the default mode (honor) to emulate # automatic enrollment params = { 'enrollment_action': 'enroll', 'course_id': unicode(self.course.id) } self.client.post(reverse('change_enrollment'), params) # Explicitly select the honor mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) self.client.post( choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[CourseMode.DEFAULT_MODE_SLUG]) # Verify that the user's enrollment remains unchanged mode, is_active = CourseEnrollment.enrollment_mode_for_user( self.user, self.course.id) self.assertEqual(mode, CourseMode.DEFAULT_MODE_SLUG) self.assertEqual(is_active, True)
def test_choose_mode_redirect(self, course_mode, expected_redirect): # Create the course modes for mode in ('audit', 'honor', 'verified'): min_price = 0 if course_mode in ["honor", "audit"] else 1 CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=min_price) # Choose the mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.post( choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[course_mode]) # Verify the redirect if expected_redirect == 'dashboard': redirect_url = reverse('dashboard') elif expected_redirect == 'start-flow': redirect_url = reverse( 'verify_student_start_flow', kwargs={'course_id': unicode(self.course.id)}) else: self.fail("Must provide a valid redirect URL name") self.assertRedirects(response, redirect_url)
def test_professional_enrollment(self, mode): # The only course mode is professional ed CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=1) # Go to the "choose your track" page choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(choose_track_url) # Since the only available track is professional ed, expect that # we're redirected immediately to the start of the payment flow. start_flow_url = reverse('verify_student_start_flow', args=[unicode(self.course.id)]) self.assertRedirects(response, start_flow_url) # Now enroll in the course CourseEnrollmentFactory( user=self.user, is_active=True, mode=mode, course_id=unicode(self.course.id), ) # Expect that this time we're redirected to the dashboard (since we're already registered) response = self.client.get(choose_track_url) self.assertRedirects(response, reverse('dashboard'))
def test_donate_button(self, course_modes, enrollment_mode, show_donate): # Enable the enrollment success message self._configure_message_timeout(10000) # Enable donations DonationConfiguration(enabled=True).save() # Create the course mode(s) for mode, min_price in course_modes: CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=min_price) self.enrollment.mode = enrollment_mode self.enrollment.save() # Check that the donate button is or is not displayed self.client.login(username=self.student.username, password=self.PASSWORD) response = self.client.get(reverse("dashboard")) if show_donate: self.assertContains(response, "donate-container") else: self.assertNotContains(response, "donate-container")
def test_enrollment_skipped_if_autoreg(self): # TODO (ECOM-16): Remove once we complete the auto-reg AB test. session = self.client.session session['auto_register'] = True session.save() # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Now enroll in the course CourseEnrollmentFactory( user=self.user, is_active=True, mode="honor", course_id=unicode(self.course.id), ) # Choose the mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['audit']) # Verify that enrollment mode is still honor mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEqual(mode, "honor") self.assertEqual(is_active, True)
def test_choose_mode_redirect(self, auto_register, course_mode, expected_redirect): # TODO (ECOM-16): Remove once we complete the auto-reg AB test. if auto_register: self.client.session['auto_register'] = True self.client.session.save() # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Choose the mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) resp = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[course_mode]) # Verify the redirect if expected_redirect == 'dashboard': redirect_url = reverse('dashboard') elif expected_redirect == 'show_requirements': redirect_url = reverse( 'verify_student_show_requirements', kwargs={'course_id': unicode(self.course.id)} ) + "?upgrade=False" else: self.fail("Must provide a valid redirect URL name") self.assertRedirects(resp, redirect_url)
def setUp(self): self.user = UserFactory.create(username="******", password="******") self.client.login(username="******", password="******") course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_key = course.id CourseModeFactory( mode_slug="professional", course_id=self.course_key, min_price=self.MIN_PRICE, suggested_prices='' ) self.urls = { 'course_modes_choose': reverse( 'course_modes_choose', args=[unicode(self.course_key)] ), 'verify_show_student_requirements': reverse( 'verify_student_show_requirements', args=[unicode(self.course_key)] ), 'verify_student_verify': reverse( 'verify_student_verify', args=[unicode(self.course_key)] ), 'verify_student_verified': reverse( 'verify_student_verified', args=[unicode(self.course_key)] ) + "?upgrade=False", }
def setUp(self): super(VerifiedUpgradeToolTest, self).setUp() self.course_verified_mode = CourseModeFactory( course_id=self.course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=self.now + datetime.timedelta(days=30), ) patcher = patch( 'openedx.core.djangoapps.schedules.signals.get_current_site') mock_get_current_site = patcher.start() self.addCleanup(patcher.stop) mock_get_current_site.return_value = SiteFactory.create() DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True) self.request = RequestFactory().request() crum.set_current_request(self.request) self.addCleanup(crum.set_current_request, None) self.enrollment = CourseEnrollmentFactory( course_id=self.course.id, mode=CourseMode.AUDIT, course=self.course_overview, ) self.request.user = self.enrollment.user
def test_enrollments_not_deleted(self): """ Recreating a CourseOverview with an outdated version should not delete the associated enrollment. """ course = CourseFactory(self_paced=True) CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=30), ) # Create a CourseOverview with an outdated version course_overview = CourseOverview.load_from_module_store(course.id) course_overview.version = CourseOverview.VERSION - 1 course_overview.save() # Create an inactive enrollment with this course overview enrollment = CourseEnrollmentFactory( user=self.user, course_id=course.id, mode=CourseMode.AUDIT, course=course_overview, ) # Re-fetch the CourseOverview record. # As a side effect, this will recreate the record, and update the version. course_overview_new = CourseOverview.get_from_id(course.id) self.assertEqual(course_overview_new.version, CourseOverview.VERSION) # Ensure that the enrollment record was unchanged during this re-creation enrollment_refetched = CourseEnrollment.objects.filter( id=enrollment.id) self.assertTrue(enrollment_refetched.exists()) self.assertEqual(enrollment_refetched.all()[0], enrollment)
def test_check_for_existing_entitlement_and_enroll(self, mock_get_course_uuid): course = CourseFactory() CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1) ) entitlement = CourseEntitlementFactory.create( mode=CourseMode.VERIFIED, user=self.user, ) mock_get_course_uuid.return_value = entitlement.course_uuid assert not CourseEnrollment.is_enrolled(user=self.user, course_key=course.id) CourseEntitlement.check_for_existing_entitlement_and_enroll( user=self.user, course_run_key=course.id, ) assert CourseEnrollment.is_enrolled(user=self.user, course_key=course.id) entitlement.refresh_from_db() assert entitlement.enrollment_course_run
def test_professional_enrollment(self): # The only course mode is professional ed CourseModeFactory(mode_slug='professional', course_id=self.course.id) # Go to the "choose your track" page choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(choose_track_url) # Expect that we're redirected immediately to the "show requirements" page # (since the only available track is professional ed) show_reqs_url = reverse('verify_student_show_requirements', args=[unicode(self.course.id)]) self.assertRedirects(response, show_reqs_url) # Now enroll in the course CourseEnrollmentFactory( user=self.user, is_active=True, mode="professional", course_id=unicode(self.course.id), ) # Expect that this time we're redirected to the dashboard (since we're already registered) response = self.client.get(choose_track_url) self.assertRedirects(response, reverse('dashboard'))
def setUp(self): """ Create a user and course. """ self.user = UserFactory.create(username="******", password="******") self.course = CourseFactory.create() for mode in ('audit', 'honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) self.client.login(username="******", password="******")
def setUp(self): super(TestProfEdVerification, self).setUp() self.user = UserFactory.create(username="******", password="******") self.client.login(username="******", password="******") course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_key = course.id CourseModeFactory( mode_slug="professional", course_id=self.course_key, min_price=self.MIN_PRICE, suggested_prices='' ) self.urls = { 'course_modes_choose': reverse( 'course_modes_choose', args=[unicode(self.course_key)] ), 'verify_student_start_flow': reverse( 'verify_student_start_flow', args=[unicode(self.course_key)] ), }
def test_redirect_to_dashboard(self, is_active, enrollment_mode, upgrade, redirect): # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Enroll the user in the test course CourseEnrollmentFactory(is_active=is_active, mode=enrollment_mode, course_id=self.course.id, user=self.user) # Configure whether we're upgrading or not get_params = {} if upgrade: get_params = {'upgrade': True} url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url, get_params) # Check whether we were correctly redirected if redirect: self.assertRedirects(response, reverse('dashboard')) else: self.assertEquals(response.status_code, 200)
def test_check_for_no_entitlement_and_do_not_enroll( self, mock_get_course_uuid): course = CourseFactory() CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1)) entitlement = CourseEntitlementFactory.create( mode=CourseMode.VERIFIED, user=self.user, ) mock_get_course_uuid.return_value = None assert not CourseEnrollment.is_enrolled(user=self.user, course_key=course.id) CourseEntitlement.check_for_existing_entitlement_and_enroll( user=self.user, course_run_key=course.id, ) assert not CourseEnrollment.is_enrolled(user=self.user, course_key=course.id) entitlement.refresh_from_db() assert entitlement.enrollment_course_run is None new_course = CourseFactory() CourseModeFactory( course_id=new_course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1)) # Return invalid uuid so that no entitlement returned for this new course mock_get_course_uuid.return_value = uuid4().hex try: CourseEntitlement.check_for_existing_entitlement_and_enroll( user=self.user, course_run_key=new_course.id, ) assert not CourseEnrollment.is_enrolled(user=self.user, course_key=new_course.id) except AttributeError as error: self.fail(error.message)
def add_to_cart(self): """ Adds content to self.user's cart """ course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course') CourseModeFactory(course_id=course.id) cart = Order.get_cart_for_user(self.user) PaidCourseRegistration.add_to_order(cart, course.id)
def test_suggested_prices(self, price_list): # Create the course modes for mode in ('audit', 'honor'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory(mode_slug='verified', course_id=self.course.id, suggested_prices=price_list) # Verify that the prices render correctly response = self.client.get( reverse('course_modes_choose', args=[unicode(self.course.id)]), follow=False, ) self.assertEquals(response.status_code, 200)
def test_unsupported_enrollment_mode_failure(self): # Create the supported course modes for mode in ('honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Choose an unsupported mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['unsupported']) self.assertEqual(400, response.status_code)
def test_no_enrollment(self): # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory(mode_slug=mode, course_id=self.course.id) # User visits the track selection page directly without ever enrolling url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) self.assertEquals(response.status_code, 200)