def test_chunked_queries_send_numerous_emails(self, email_mock): """ Test sending a large number of emails, to test the chunked querying """ mock_factory = MockCourseEmailResult() email_mock.side_effect = mock_factory.get_mock_update_subtask_status() added_users = [] for _ in xrange(LARGE_NUM_EMAILS): user = UserFactory() added_users.append(user) CourseEnrollmentFactory.create(user=user, course_id=self.course.id) optouts = [] for i in [1, 3, 9, 10, 18]: # 5 random optouts user = added_users[i] optouts.append(user) optout = Optout(user=user, course_id=self.course.id) optout.save() test_email = { 'action': 'Send email', 'to_option': 'all', 'subject': 'test subject for all', 'message': 'test message for all' } response = self.client.post(self.url, test_email) self.assertContains(response, "Your email was successfully queued for sending.") self.assertEquals(mock_factory.emails_sent, 1 + len(self.staff) + len(self.students) + LARGE_NUM_EMAILS - len(optouts)) outbox_contents = [e.to[0] for e in mail.outbox] should_send_contents = ([self.instructor.email] + [s.email for s in self.staff] + [s.email for s in self.students] + [s.email for s in added_users if s not in optouts]) self.assertItemsEqual(outbox_contents, should_send_contents)
def test_resolve_course_enrollments(self): """ Test that the CourseEnrollmentsScopeResolver actually returns all enrollments """ test_user_1 = UserFactory.create(password='******') CourseEnrollmentFactory(user=test_user_1, course_id=self.course.id) test_user_2 = UserFactory.create(password='******') CourseEnrollmentFactory(user=test_user_2, course_id=self.course.id) test_user_3 = UserFactory.create(password='******') enrollment = CourseEnrollmentFactory(user=test_user_3, course_id=self.course.id) # unenroll #3 enrollment.is_active = False enrollment.save() resolver = CourseEnrollmentsScopeResolver() user_ids = resolver.resolve('course_enrollments', {'course_id': self.course.id}, None) # should have first two, but the third should not be present self.assertTrue(test_user_1.id in user_ids) self.assertTrue(test_user_2.id in user_ids) self.assertFalse(test_user_3.id in user_ids)
def setUp(self): course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ" self.course = CourseFactory.create(display_name=course_title) self.instructor = InstructorFactory(course=self.course.location) # Create staff self.staff = [StaffFactory(course=self.course.location) for _ in xrange(STAFF_COUNT)] # Create students self.students = [UserFactory() for _ in xrange(STUDENT_COUNT)] for student in self.students: CourseEnrollmentFactory.create(user=student, course_id=self.course.id) # load initial content (since we don't run migrations as part of tests): call_command("loaddata", "course_email_template.json") self.client.login(username=self.instructor.username, password="******") # Pull up email view on instructor dashboard self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id}) response = self.client.get(self.url) email_link = '<a href="#" onclick="goto(\'Email\')" class="None">Email</a>' # If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False self.assertTrue(email_link in response.content) # Select the Email view of the instructor dash session = self.client.session session['idash_mode'] = 'Email' session.save() response = self.client.get(self.url) selected_email_link = '<a href="#" onclick="goto(\'Email\')" class="selectedmode">Email</a>' self.assertTrue(selected_email_link in response.content)
def setUp(self): super(TestBlockListGetForm, self).setUp() self.student = UserFactory.create() self.student2 = UserFactory.create() self.staff = UserFactory.create(is_staff=True) CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.student2, course_id=self.course.id) usage_key = self.course.location self.initial = {'requesting_user': self.student} self.form_data = QueryDict( urlencode({ 'username': self.student.username, 'usage_key': unicode(usage_key), }), mutable=True, ) self.cleaned_data = { 'all_blocks': None, 'block_counts': set(), 'depth': 0, 'nav_depth': None, 'return_type': 'dict', 'requested_fields': {'display_name', 'type'}, 'student_view_data': set(), 'usage_key': usage_key, 'username': self.student.username, 'user': self.student, }
def setup_students_and_grades(context): """ Create students and set their grades. :param context: class reference """ if context.course: context.student = student = UserFactory.create() CourseEnrollmentFactory.create(user=student, course_id=context.course.id) context.student2 = student2 = UserFactory.create() CourseEnrollmentFactory.create(user=student2, course_id=context.course.id) # create grades for self.student as if they'd submitted the ccx for chapter in context.course.get_children(): for i, section in enumerate(chapter.get_children()): for j, problem in enumerate(section.get_children()): # if not problem.visible_to_staff_only: StudentModuleFactory.create( grade=1 if i < j else 0, max_grade=1, student=context.student, course_id=context.course.id, module_state_key=problem.location ) StudentModuleFactory.create( grade=1 if i > j else 0, max_grade=1, student=context.student2, course_id=context.course.id, module_state_key=problem.location )
def test_masquerade_expired(self, mock_get_course_run_details): mock_get_course_run_details.return_value = {'weeks_to_complete': 1} audit_student = UserFactory(username='******') enrollment = CourseEnrollmentFactory.create( user=audit_student, course_id=self.course.id, mode='audit', ) enrollment.created = self.course.start enrollment.save() CourseDurationLimitConfig.objects.create( enabled=True, course=CourseOverview.get_from_id(self.course.id), enabled_as_of=self.course.start, ) instructor = UserFactory.create(username='******') CourseEnrollmentFactory.create( user=instructor, course_id=self.course.id, mode='audit' ) CourseInstructorRole(self.course.id).add_users(instructor) self.client.login(username=instructor.username, password='******') self.update_masquerade(username='******') course_home_url = reverse('openedx.course_experience.course_home', args=[six.text_type(self.course.id)]) response = self.client.get(course_home_url, follow=True) self.assertEqual(response.status_code, 200) self.assertItemsEqual(response.redirect_chain, []) banner_text = 'This learner does not have access to this course. Their access expired on' self.assertIn(banner_text, response.content)
def _create_cert(self, course_key, user, status): """Create a certificate entry. """ # Enroll the user in the course CourseEnrollmentFactory.create(user=user, course_id=course_key) # Create the certificate GeneratedCertificate.objects.create(user=user, course_id=course_key, status=status)
def setUp(self): super(TestGradebook, self).setUp() instructor = AdminFactory.create() self.client.login(username=instructor.username, password='******') self.users = [UserFactory.create() for _ in xrange(USER_COUNT)] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) for i, item in enumerate(self.items): for j, user in enumerate(self.users): StudentModuleFactory.create( grade=1 if i < j else 0, max_grade=1, student=user, course_id=self.course.id, module_state_key=item.location ) self.response = self.client.get(reverse( 'spoc_gradebook', args=(self.course.id.to_deprecated_string(),) )) self.assertEquals(self.response.status_code, 200)
def setUp(self): super(CCXCoachTabTestCase, self).setUp() self.user = UserFactory.create() for course in [self.ccx_enabled_course, self.ccx_disabled_course]: CourseEnrollmentFactory.create(user=self.user, course_id=course.id) role = CourseCcxCoachRole(course.id) role.add_users(self.user)
def setUp(self): """ Setup course structure and create user for split test transformer test. """ super(SplitTestTransformerTestCase, self).setUp() # Set up user partitions and groups. self.groups = [Group(1, 'Group 1'), Group(2, 'Group 2'), Group(3, 'Group 3')] self.split_test_user_partition_id = self.TEST_PARTITION_ID self.split_test_user_partition = UserPartition( id=self.split_test_user_partition_id, name='Split Partition', description='This is split partition', groups=self.groups, scheme=RandomUserPartitionScheme ) self.split_test_user_partition.scheme.name = "random" # Build course. self.course_hierarchy = self.get_course_hierarchy() self.blocks = self.build_course(self.course_hierarchy) self.course = self.blocks['course'] # Enroll user in course. CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id, is_active=True) self.transformer = UserPartitionTransformer()
def setUp(self): super(TestGetProblemGradeDistribution, self).setUp() self.request_factory = RequestFactory() self.instructor = AdminFactory.create() self.client.login(username=self.instructor.username, password='******') self.attempts = 3 self.course = CourseFactory.create( display_name=u"test course omega \u03a9", ) section = ItemFactory.create( parent_location=self.course.location, category="chapter", display_name=u"test factory section omega \u03a9", ) self.sub_section = ItemFactory.create( parent_location=section.location, category="sequential", display_name=u"test subsection omega \u03a9", ) unit = ItemFactory.create( parent_location=self.sub_section.location, category="vertical", metadata={'graded': True, 'format': 'Homework'}, display_name=u"test unit omega \u03a9", ) self.users = [UserFactory.create(username="******" + str(__)) for __ in xrange(USER_COUNT)] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) for i in xrange(USER_COUNT - 1): category = "problem" self.item = ItemFactory.create( parent_location=unit.location, category=category, data=StringResponseXMLFactory().build_xml(answer='foo'), metadata={'rerandomize': 'always'}, display_name=u"test problem omega \u03a9 " + str(i) ) for j, user in enumerate(self.users): StudentModuleFactory.create( grade=1 if i < j else 0, max_grade=1 if i < j else 0.5, student=user, course_id=self.course.id, module_state_key=self.item.location, state=json.dumps({'attempts': self.attempts}), ) for j, user in enumerate(self.users): StudentModuleFactory.create( course_id=self.course.id, module_type='sequential', module_state_key=self.item.location, )
def setUp(self): super(CertificatesViewsTests, self).setUp() self.client = Client() self.course = CourseFactory.create( org='testorg', number='run1', display_name='refundable course' ) self.course_id = self.course.location.course_key self.user = UserFactory.create( email='*****@*****.**', username='******', password='******' ) self.user.profile.name = "Joe User" self.user.profile.save() self.client.login(username=self.user.username, password='******') self.request = RequestFactory().request() self.cert = GeneratedCertificateFactory.create( user=self.user, course_id=self.course_id, download_uuid=uuid4(), download_url="http://www.example.com/certificates/download", grade="0.95", key='the_key', distinction=True, status='downloadable', mode='honor', name=self.user.profile.name, ) CourseEnrollmentFactory.create( user=self.user, course_id=self.course_id ) CertificateHtmlViewConfigurationFactory.create() LinkedInAddToProfileConfigurationFactory.create()
def setup_course(self): self.course = CourseFactory.create(data=self.COURSE_DATA) # Turn off cache. modulestore().request_cache = None modulestore().metadata_inheritance_cache_subsystem = None chapter = ItemFactory.create( parent_location=self.course.location, category="sequential", ) self.section = ItemFactory.create( parent_location=chapter.location, category="sequential" ) # username = robot{0}, password = '******' self.users = [ UserFactory.create() for i in range(self.USER_COUNT) ] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) # login all users for acces to Xmodule self.clients = {user.username: Client() for user in self.users} self.login_statuses = [ self.clients[user.username].login( username=user.username, password='******') for user in self.users ] self.assertTrue(all(self.login_statuses))
def setUp(self): super(TestBlockListGetForm, self).setUp() self.student = UserFactory.create() self.student2 = UserFactory.create() self.staff = UserFactory.create(is_staff=True) CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.student2, course_id=self.course.id) usage_key = self.course.location self.initial = {"requesting_user": self.student} self.form_data = QueryDict( urlencode({"username": self.student.username, "usage_key": unicode(usage_key)}), mutable=True ) self.cleaned_data = { "all_blocks": None, "block_counts": set(), "depth": 0, "nav_depth": None, "return_type": "dict", "requested_fields": {"display_name", "type"}, "student_view_data": set(), "usage_key": usage_key, "username": self.student.username, "user": self.student, }
def _create_user(self, username, email=None, is_staff=False, mode="honor"): """Creates a user and enrolls them in the test course.""" if email is None: email = InstructorTaskCourseTestCase.get_user_email(username) thisuser = UserFactory.create(username=username, email=email, is_staff=is_staff) CourseEnrollmentFactory.create(user=thisuser, course_id=self.course.id, mode=mode) return thisuser
def setUp(self): self.course_name = 'edX/toy/2012_Fall' # Create student account student = UserFactory.create() CourseEnrollmentFactory.create( user=student, course_id=SlashSeparatedCourseKey.from_deprecated_string(self.course_name) ) self.client.login(username=student.username, password="******") try: # URL for dashboard self.url = reverse('dashboard') except NoReverseMatch: raise SkipTest("Skip this test if url cannot be found (ie running from CMS tests)") # URL for email settings modal self.email_modal_link = ( ('<a href="#email-settings-modal" class="email-settings" rel="leanModal" ' 'data-course-id="{0}/{1}/{2}" data-course-number="{1}" ' 'data-optout="False">Email Settings</a>').format( 'edX', 'toy', '2012_Fall' ) )
def create_course(self, modules_count, module_store, topics): """ Create a course in a specified module store with discussion module and topics """ course = CourseFactory.create( org="a", course="b", run="c", start=datetime.now(UTC), default_store=module_store, discussion_topics=topics ) CourseEnrollmentFactory.create(user=self.user, course_id=course.id) course_url = reverse("course_topics", kwargs={"course_id": unicode(course.id)}) # add some discussion modules for i in range(modules_count): ItemFactory.create( parent_location=course.location, category='discussion', discussion_id='id_module_{}'.format(i), discussion_category='Category {}'.format(i), discussion_target='Discussion {}'.format(i), publish_item=False, ) return course_url
def test_data_err_fail(self, retry, result): """ Test that celery handles permanent SMTPDataErrors by failing and not retrying. """ self.smtp_server_thread.server.set_errtype( "DATA", "554 Message rejected: Email address is not verified." ) students = [UserFactory() for _ in xrange(settings.EMAILS_PER_TASK)] for student in students: CourseEnrollmentFactory.create(user=student, course_id=self.course.id) test_email = { 'action': 'Send email', 'to_option': 'all', 'subject': 'test subject for all', 'message': 'test message for all' } self.client.post(self.url, test_email) # We shouldn't retry when hitting a 5xx error self.assertFalse(retry.called) # Test that after the rejected email, the rest still successfully send ((sent, fail, optouts), _) = result.call_args self.assertEquals(optouts, 0) self.assertEquals(fail, 1) self.assertEquals(sent, settings.EMAILS_PER_TASK - 1)
def test_access_masquerade_as_user_with_forum_role(self, role_name): """ Test that when masquerading as a user with a given forum role you do not lose access to graded content """ staff_user = StaffFactory.create(password=TEST_PASSWORD, course_key=self.course.id) CourseEnrollmentFactory.create( user=staff_user, course_id=self.course.id, mode='audit' ) self.client.login(username=staff_user.username, password=TEST_PASSWORD) user = UserFactory.create() role = RoleFactory(name=role_name, course_id=self.course.id) role.users.add(user) CourseEnrollmentFactory.create( user=user, course_id=self.course.id, mode='audit' ) self.update_masquerade(username=user.username) _assert_block_is_gated( block=self.blocks_dict['problem'], user=user, course=self.course, is_gated=False, request_factory=self.factory, )
def test_double_denied(self): ''' First graded problem should show message, second shouldn't ''' course = self._create_course() blocks_dict = course['blocks'] blocks_dict['graded_1'] = ItemFactory.create( parent=blocks_dict['vertical'], category='problem', graded=True, metadata=METADATA, ) blocks_dict['graded_2'] = ItemFactory.create( parent=blocks_dict['vertical'], category='problem', graded=True, metadata=METADATA, ) CourseEnrollmentFactory.create( user=self.user, course_id=course['course'].id, mode='audit' ) _assert_block_is_gated( block=blocks_dict['graded_1'], user=self.user, course=course['course'], is_gated=True, request_factory=self.request_factory, ) _assert_block_is_empty( block=blocks_dict['graded_2'], user_id=self.user.id, course=course['course'], request_factory=self.request_factory, )
def test_access_masquerade_as_course_team_users(self, role_factory): """ Test that when masquerading as members of the course team you do not lose access to graded content """ # There are two types of course team members: instructor and staff # they have different privileges, but for the purpose of this test the important thing is that they should both # have access to all graded content staff_user = StaffFactory.create(password=TEST_PASSWORD, course_key=self.course.id) CourseEnrollmentFactory.create( user=staff_user, course_id=self.course.id, mode='audit' ) self.client.login(username=staff_user.username, password=TEST_PASSWORD) if role_factory == GlobalStaffFactory: user = role_factory.create() else: user = role_factory.create(course_key=self.course.id) self.update_masquerade(username=user.username) block = self.blocks_dict['problem'] block_view_url = reverse('render_xblock', kwargs={'usage_key_string': six.text_type(block.scope_ids.usage_id)}) response = self.client.get(block_view_url) self.assertEquals(response.status_code, 200)
def test_access_course_team_users(self, role_factory): """ Test that members of the course team do not lose access to graded content """ # There are two types of course team members: instructor and staff # they have different privileges, but for the purpose of this test the important thing is that they should both # have access to all graded content if role_factory == GlobalStaffFactory: user = role_factory.create() else: user = role_factory.create(course_key=self.course.id) CourseEnrollmentFactory.create( user=user, course_id=self.course.id, mode='audit', ) # assert that course team members have access to graded content _assert_block_is_gated( block=self.blocks_dict['problem'], user=user, course=self.course, is_gated=False, request_factory=self.factory, )
def setUp(self): """ Create the test data. """ super(CompletionBatchTestCase, self).setUp() self.url = reverse('completion_api:v1:completion-batch') # Enable the waffle flag for all tests self.override_waffle_switch(True) # Create course self.course = CourseFactory.create(org='TestX', number='101', display_name='Test') self.problem = ItemFactory.create( parent=self.course, category="problem", display_name="Test Problem", ) # Create users self.staff_user = UserFactory(is_staff=True) self.enrolled_user = UserFactory(username=self.ENROLLED_USERNAME) self.unenrolled_user = UserFactory(username=self.UNENROLLED_USERNAME) # Enrol one user in the course CourseEnrollmentFactory.create(user=self.enrolled_user, course_id=self.course.id) # Login the enrolled user by for all tests self.client = APIClient() self.client.force_authenticate(user=self.enrolled_user)
def test_unicode_students_send_to_all(self): """ Make sure email (with Unicode characters) send to all goes there. """ # Now we know we have pulled up the instructor dash's email view # (in the setUp method), we can test sending an email. # Create a student with Unicode in their first & last names unicode_user = UserFactory(first_name=u'Ⓡⓞⓑⓞⓣ', last_name=u'ՇﻉรՇ') CourseEnrollmentFactory.create(user=unicode_user, course_id=self.course.id) self.students.append(unicode_user) test_email = { 'action': 'Send email', 'send_to': 'all', 'subject': 'test subject for all', 'message': 'test message for all' } # Post the email to the instructor dashboard API response = self.client.post(self.send_mail_url, test_email) self.assertEquals(json.loads(response.content), self.success_content) self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students)) self.assertItemsEqual( [e.to[0] for e in mail.outbox], [self.instructor.email] + [s.email for s in self.staff] + [s.email for s in self.students] )
def setUp(self): super(TestGetProblemGradeDistribution, self).setUp() self.request_factory = RequestFactory() self.instructor = AdminFactory.create() self.client.login(username=self.instructor.username, password='******') self.attempts = 3 self.users = [ UserFactory.create(username="******" + str(__)) for __ in xrange(USER_COUNT) ] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) for i, item in enumerate(self.items): for j, user in enumerate(self.users): StudentModuleFactory.create( grade=1 if i < j else 0, max_grade=1 if i < j else 0.5, student=user, course_id=self.course.id, module_state_key=item.location, state=json.dumps({'attempts': self.attempts}), ) for j, user in enumerate(self.users): StudentModuleFactory.create( course_id=self.course.id, module_type='sequential', module_state_key=item.location, )
def setUp(self): course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ" self.course = CourseFactory.create(display_name=course_title) self.instructor = InstructorFactory(course=self.course.id) # Create staff self.staff = [StaffFactory(course=self.course.id) for _ in xrange(STAFF_COUNT)] # Create students self.students = [UserFactory() for _ in xrange(STUDENT_COUNT)] for student in self.students: CourseEnrollmentFactory.create(user=student, course_id=self.course.id) # load initial content (since we don't run migrations as part of tests): call_command("loaddata", "course_email_template.json") self.client.login(username=self.instructor.username, password="******") # Pull up email view on instructor dashboard self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}) # Response loads the whole instructor dashboard, so no need to explicitly # navigate to a particular email section response = self.client.get(self.url) email_section = '<div class="vert-left send-email" id="section-send-email">' # If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False self.assertTrue(email_section in response.content) self.send_mail_url = reverse('send_email', kwargs={'course_id': self.course.id.to_deprecated_string()}) self.success_content = { 'course_id': self.course.id.to_deprecated_string(), 'success': True, }
def setUp(self): super(DiscussionTabTestCase, self).setUp() self.course = CourseFactory.create() self.enrolled_user = UserFactory.create() self.staff_user = AdminFactory.create() CourseEnrollmentFactory.create(user=self.enrolled_user, course_id=self.course.id) self.unenrolled_user = UserFactory.create()
def setUp(self): self.partition = UserPartition( 0, 'first_partition', 'First Partition', [ Group(0, 'alpha'), Group(1, 'beta') ] ) self.course = CourseFactory.create( number=self.COURSE_NUMBER, user_partitions=[self.partition] ) self.chapter = ItemFactory.create( parent_location=self.course.location, category="chapter", display_name="test chapter", ) self.sequential = ItemFactory.create( parent_location=self.chapter.location, category="sequential", display_name="Split Test Tests", ) self.student = UserFactory.create() CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) self.client.login(username=self.student.username, password='******')
def test_unicode_students_send_to_all(self): """ Make sure email (with Unicode characters) send to all goes there. """ # Create a student with Unicode in their first & last names unicode_user = UserFactory(first_name=u'Ⓡⓞⓑⓞⓣ', last_name=u'ՇﻉรՇ') CourseEnrollmentFactory.create(user=unicode_user, course_id=self.course.id) self.students.append(unicode_user) test_email = { 'action': 'Send email', 'send_to': '["myself", "staff", "learners"]', 'subject': 'test subject for all', 'message': 'test message for all' } response = self.client.post(self.send_mail_url, test_email) self.assertEquals(json.loads(response.content), self.success_content) self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students)) self.assertItemsEqual( [e.to[0] for e in mail.outbox], [self.instructor.email] + [s.email for s in self.staff] + [s.email for s in self.students] )
def test_data_err_fail(self, retry, result, get_conn): """ Test that celery handles permanent SMTPDataErrors by failing and not retrying. """ # have every fourth email fail due to blacklisting: get_conn.return_value.send_messages.side_effect = cycle([SMTPDataError(554, "Email address is blacklisted"), None, None, None]) students = [UserFactory() for _ in xrange(settings.BULK_EMAIL_EMAILS_PER_TASK)] for student in students: CourseEnrollmentFactory.create(user=student, course_id=self.course.id) test_email = { 'action': 'Send email', 'send_to': 'all', 'subject': 'test subject for all', 'message': 'test message for all' } response = self.client.post(self.send_mail_url, test_email) self.assertEquals(json.loads(response.content), self.success_content) # We shouldn't retry when hitting a 5xx error self.assertFalse(retry.called) # Test that after the rejected email, the rest still successfully send ((_entry_id, _current_task_id, subtask_status), _kwargs) = result.call_args self.assertEquals(subtask_status.skipped, 0) expected_fails = int((settings.BULK_EMAIL_EMAILS_PER_TASK + 3) / 4.0) self.assertEquals(subtask_status.failed, expected_fails) self.assertEquals(subtask_status.succeeded, settings.BULK_EMAIL_EMAILS_PER_TASK - expected_fails)
def test_student_has_access(self): """ Tests course student have right access to content w/o preview. """ course_key = self.course.id chapter = ItemFactory.create(category="chapter", parent_location=self.course.location) overview = CourseOverview.get_from_id(course_key) # Enroll student to the course CourseEnrollmentFactory(user=self.student, course_id=self.course.id) modules = [ self.course, overview, chapter, ] with patch('courseware.access.in_preview_mode') as mock_preview: mock_preview.return_value = False for obj in modules: self.assertTrue( bool( access.has_access(self.student, 'load', obj, course_key=self.course.id))) with patch('courseware.access.in_preview_mode') as mock_preview: mock_preview.return_value = True for obj in modules: self.assertFalse( bool( access.has_access(self.student, 'load', obj, course_key=self.course.id)))
def test_access_on_course_with_pre_requisites(self): """ Test course access when a course has pre-requisite course yet to be completed """ seed_milestone_relationship_types() user = UserFactory.create() pre_requisite_course = CourseFactory.create(org='test_org', number='788', run='test_run') pre_requisite_courses = [unicode(pre_requisite_course.id)] course = CourseFactory.create( org='test_org', number='786', run='test_run', pre_requisite_courses=pre_requisite_courses) set_prerequisite_courses(course.id, pre_requisite_courses) # user should not be able to load course even if enrolled CourseEnrollmentFactory(user=user, course_id=course.id) response = access._has_access_course_desc( user, 'view_courseware_with_prerequisites', course) self.assertFalse(response) self.assertIsInstance(response, access_response.MilestoneError) # Staff can always access course staff = StaffFactory.create(course_key=course.id) self.assertTrue( access._has_access_course_desc( staff, 'view_courseware_with_prerequisites', course)) # User should be able access after completing required course fulfill_course_milestone(pre_requisite_course.id, user) self.assertTrue( access._has_access_course_desc( user, 'view_courseware_with_prerequisites', course))
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_get_visible_sessions_for_entitlement_expired_mode(self, mock_get_edx_api_data): """ Test retrieval of visible session entitlements. """ catalog_course_run = CourseRunFactory.create() catalog_course = CourseFactory(course_runs=[catalog_course_run]) mock_get_edx_api_data.return_value = catalog_course course_key = CourseKey.from_string(catalog_course_run.get('key')) course_overview = CourseOverviewFactory.create(id=course_key, start=self.tomorrow) CourseModeFactory.create( mode_slug=CourseMode.VERIFIED, min_price=100, course_id=course_overview.id, expiration_datetime=now() - timedelta(days=1) ) course_enrollment = CourseEnrollmentFactory( user=self.user, course_id=unicode(course_overview.id), mode=CourseMode.VERIFIED ) entitlement = CourseEntitlementFactory( user=self.user, enrollment_course_run=course_enrollment, mode=CourseMode.VERIFIED ) session_entitlements = get_visible_sessions_for_entitlement(entitlement) self.assertEqual(session_entitlements, [catalog_course_run])
def test_username_exact_match(self): """ Ensure that course enrollment searches return exact matches on username first. """ user2 = UserFactory.create( username='******'.format(self.user.username)) CourseEnrollmentFactory( user=user2, course_id=self.course.id, # pylint: disable=no-member ) search_url = '{}?q={}'.format( reverse('admin:student_courseenrollment_changelist'), self.user.username) with COURSE_ENROLLMENT_ADMIN_SWITCH.override(active=True): response = self.client.get(search_url) self.assertEqual(response.status_code, 200) # context['results'] is an array of arrays of HTML <td> elements to be rendered self.assertEqual(len(response.context['results']), 2) for idx, username in enumerate([self.user.username, user2.username]): # Locate the <td> column containing the username user_field = next(col for col in response.context['results'][idx] if "field-user" in col) self.assertIn(username, user_field)
def test_learner_already_enrolled_in_course(self): course_key = self.course_keys[0] course = CourseOverview.objects.get(id=course_key) CourseEnrollmentFactory(user=self.user, course=course, mode=CourseMode.VERIFIED) program_enrollment = self._create_waiting_program_enrollment() program_course_enrollments = self._create_waiting_course_enrollments( program_enrollment) UserSocialAuth.objects.create(user=self.user, uid='{0}:{1}'.format( self.provider_slug, self.external_id)) self._assert_program_enrollment_user(program_enrollment, self.user) duplicate_program_course_enrollment = program_course_enrollments[0] self._assert_program_course_enrollment( duplicate_program_course_enrollment, CourseMode.VERIFIED) program_course_enrollment = program_course_enrollments[1] self._assert_program_course_enrollment(program_course_enrollment)
def test_suggested_prices(self, price_list): # Create the course modes for mode in ('audit', 'honor'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(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=[six.text_type(self.course.id)]), follow=False, ) self.assertEquals(response.status_code, 200)
def test_student_enrollment_status(self, is_enrolled, enrolled_mode, is_upgrade_required, mock_get_mode): """Verify that program data is supplemented with the student's enrollment status.""" expected_upgrade_url = '{root}/{path}?sku={sku}'.format( root=ECOMMERCE_URL_ROOT, path=self.checkout_path.strip('/'), sku=self.sku, ) update_commerce_config(enabled=True, checkout_page=self.checkout_path) mock_mode = mock.Mock() mock_mode.sku = self.sku mock_get_mode.return_value = mock_mode if is_enrolled: CourseEnrollmentFactory(user=self.user, course_id=self.course.id, mode=enrolled_mode) data = ProgramDataExtender(self.program, self.user).extend() self._assert_supplemented( data, is_enrolled=is_enrolled, upgrade_url=expected_upgrade_url if is_upgrade_required else None )
def test_with_course_data(self, mock_get_current_site): self.highlights_patcher.stop() mock_get_current_site.return_value = self.site_config.site course = CourseFactory(highlights_enabled_for_messaging=True, self_paced=True) with self.store.bulk_operations(course.id): ItemFactory.create(parent=course, category='chapter', highlights=[u'highlights']) enrollment = CourseEnrollmentFactory(course_id=course.id, user=self.user, mode=u'audit') self.assertEqual(enrollment.schedule.get_experience_type(), ScheduleExperience.EXPERIENCES.course_updates) _, offset, target_day, _ = self._get_dates(offset=self.expected_offsets[0]) enrollment.schedule.start = target_day enrollment.schedule.save() with patch.object(tasks, 'ace') as mock_ace: self.task().apply(kwargs=dict( # pylint: disable=no-value-for-parameter site_id=self.site_config.site.id, target_day_str=serialize(target_day), day_offset=offset, bin_num=self._calculate_bin_for_user(enrollment.user), )) self.assertTrue(mock_ace.send.called)
def _create_courses_and_enrollments(self, *args): """Create courses and enrollments. Created courses and enrollments are stored in instance variables so tests can refer to them later. Arguments: *args: Tuples of (course_org, should_enroll), where course_org is the name of the org in the course key and should_enroll is a boolean indicating whether to enroll the user in the course. Returns: None """ for course_number, (course_org, should_enroll) in enumerate(args): course = CourseFactory.create(org=course_org, number=str(course_number)) if should_enroll: enrollment = CourseEnrollmentFactory.create( is_active=True, course_id=course.id, user=self.user) self.enrollments[course.id].append(enrollment) self.courses.append(course)
def test_content_gating_course_card_changes(self): """ When a course is expired, the links on the course card should be removed. Links will be removed from the course title, course image and button (View Course/Resume Course). The course card should have an access expired message. """ CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=self.THREE_YEARS_AGO - timedelta(days=30)) self.override_waffle_switch(True) course = CourseFactory.create(start=self.THREE_YEARS_AGO) add_course_mode(course, mode_slug=CourseMode.AUDIT) add_course_mode(course) enrollment = CourseEnrollmentFactory.create( user=self.user, course_id=course.id ) enrollment.created = self.THREE_YEARS_AGO + timedelta(days=1) enrollment.save() # pylint: disable=unused-variable schedule = ScheduleFactory(enrollment=enrollment) response = self.client.get(reverse('dashboard')) dashboard_html = self._remove_whitespace_from_response(response) access_expired_substring = 'Accessexpired' course_link_class = 'course-target-link' self.assertNotIn( course_link_class, dashboard_html ) self.assertIn( access_expired_substring, dashboard_html )
def test_masquerade(self, masquerade_config, show_expiration_banner, mock_get_course_run_details): mock_get_course_run_details.return_value = {'weeks_to_complete': 12} audit_student = UserFactory(username='******') CourseEnrollmentFactory.create( user=audit_student, course_id=self.course.id, mode='audit' ) verified_student = UserFactory(username='******') CourseEnrollmentFactory.create( user=verified_student, course_id=self.course.id, mode='verified' ) CourseDurationLimitConfig.objects.create( enabled=True, course=CourseOverview.get_from_id(self.course.id), enabled_as_of=self.course.start, ) instructor = UserFactory.create(username='******') CourseEnrollmentFactory.create( user=instructor, course_id=self.course.id, mode='audit' ) CourseInstructorRole(self.course.id).add_users(instructor) self.client.login(username=instructor.username, password='******') self.update_masquerade(**masquerade_config) course_home_url = reverse('openedx.course_experience.course_home', args=[six.text_type(self.course.id)]) response = self.client.get(course_home_url, follow=True) self.assertEqual(response.status_code, 200) six.assertCountEqual(self, response.redirect_chain, []) banner_text = 'You lose all access to this course, including your progress,' if show_expiration_banner: self.assertContains(response, banner_text) else: self.assertNotContains(response, banner_text)
def setUp(self): super(TestModels, self).setUp() self.course = CourseOverviewFactory.create(start=datetime.utcnow()) self.enrollment = CourseEnrollmentFactory.create( course_id=self.course.id)
def test_spoc_gradebook_mongo_calls(self): """ Test that the MongoDB cache is used in API to return grades """ # prepare course structure course = ItemFactory.create( parent_location=self.course.location, category="course", display_name="Test course", ) students = [] for i in range(20): username = "******" % i student = UserFactory.create(username=username) CourseEnrollmentFactory.create(user=student, course_id=self.course.id) students.append(student) chapter = ItemFactory.create( parent=course, category='chapter', display_name="Chapter", publish_item=True, start=datetime.datetime(2015, 3, 1, tzinfo=UTC), ) sequential = ItemFactory.create( parent=chapter, category='sequential', display_name="Lesson", publish_item=True, start=datetime.datetime(2015, 3, 1, tzinfo=UTC), metadata={'graded': True, 'format': 'Homework'}, ) vertical = ItemFactory.create( parent=sequential, category='vertical', display_name='Subsection', publish_item=True, start=datetime.datetime(2015, 4, 1, tzinfo=UTC), ) for i in range(10): problem = ItemFactory.create( category="problem", parent=vertical, display_name=u"A Problem Block %d" % i, weight=1, publish_item=False, metadata={'rerandomize': 'always'}, ) for j in students: grade = i % 2 StudentModuleFactory.create( grade=grade, max_grade=1, student=j, course_id=self.course.id, module_state_key=problem.location ) # check MongoDB calls count url = reverse('spoc_gradebook', kwargs={'course_id': self.course.id}) with check_mongo_calls(9): response = self.client.get(url) self.assertEqual(response.status_code, 200)
class VerifiedUpgradeToolTest(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): super(VerifiedUpgradeToolTest, cls).setUpClass() cls.now = datetime.datetime.now(pytz.UTC) cls.course = CourseFactory.create( org='edX', number='test', display_name='Test Course', self_paced=True, start=cls.now - datetime.timedelta(days=30), ) cls.course_overview = CourseOverview.get_from_id(cls.course.id) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True) 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_tool_visible(self): self.assertTrue(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_no_enrollment_exists(self): self.enrollment.delete() request = RequestFactory().request() request.user = UserFactory() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_using_deadline_from_course_mode(self): DynamicUpgradeDeadlineConfiguration.objects.create(enabled=False) self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_enrollment_is_inactive(self): self.enrollment.is_active = False self.enrollment.save() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_already_verified(self): self.enrollment.mode = CourseMode.VERIFIED self.enrollment.save() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_no_verified_track(self): self.course_verified_mode.delete() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_course_deadline_has_passed(self): self.course_verified_mode.expiration_datetime = self.now - datetime.timedelta( days=1) self.course_verified_mode.save() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id)) def test_not_visible_when_course_mode_has_no_deadline(self): self.course_verified_mode.expiration_datetime = None self.course_verified_mode.save() self.assertFalse(VerifiedUpgradeTool().is_enabled( self.request, self.course.id))
def test_dashboard_with_resume_buttons_and_view_buttons(self): ''' The Test creates a four-course-card dashboard. The user completes course blocks in the even-numbered course cards. The test checks that courses with completion data have course cards with "Resume Course" buttons; those without have "View Course" buttons. ''' self.override_waffle_switch(True) isEven = lambda n: n % 2 == 0 num_course_cards = 4 html_for_view_buttons = [] html_for_resume_buttons = [] html_for_entitlement = [] for i in range(num_course_cards): course = CourseFactory.create() course_enrollment = CourseEnrollmentFactory( user=self.user, course_id=course.id ) course_key = course_enrollment.course_id course_key_string = str(course_key) if i == 1: CourseEntitlementFactory.create(user=self.user, enrollment_course_run=course_enrollment) else: last_completed_block_string = '' course_run_string = self._pull_course_run_from_course_key( course_key_string) # Submit completed course blocks in even-numbered courses. if isEven(i): block_keys = [ ItemFactory.create( category='video', parent_location=course.location, display_name='Video {0}'.format(six.text_type(number)) ).location for number in range(5) ] last_completed_block_string = str(block_keys[-1]) submit_completions_for_testing(self.user, block_keys) html_for_view_buttons.append( self._get_html_for_view_course_button( course_key_string, course_run_string ) ) html_for_resume_buttons.append( self._get_html_for_resume_course_button( course_key_string, last_completed_block_string, course_run_string ) ) html_for_entitlement.append( self._get_html_for_entitlement_button( course_key_string ) ) response = self.client.get(reverse('dashboard')) html_for_view_buttons = [ self._remove_whitespace_from_html_string(button) for button in html_for_view_buttons ] html_for_resume_buttons = [ self._remove_whitespace_from_html_string(button) for button in html_for_resume_buttons ] html_for_entitlement = [ self._remove_whitespace_from_html_string(button) for button in html_for_entitlement ] dashboard_html = self._remove_whitespace_from_response(response) for i in range(num_course_cards): expected_button = None unexpected_button = None if i == 1: expected_button = html_for_entitlement[i] unexpected_button = html_for_view_buttons[i] + html_for_resume_buttons[i] elif isEven(i): expected_button = html_for_resume_buttons[i] unexpected_button = html_for_view_buttons[i] + html_for_entitlement[i] else: expected_button = html_for_view_buttons[i] unexpected_button = html_for_resume_buttons[i] + html_for_entitlement[i] self.assertIn( expected_button, dashboard_html ) self.assertNotIn( unexpected_button, dashboard_html )
def test_sessions_for_entitlement_course_runs(self, mock_course_overview, mock_course_runs): """ When a learner has a fulfilled entitlement for a course run in the past, there should be no availableSession data passed to the JS view. When a learner has a fulfilled entitlement for a course run enrollment ending in the future, there should not be an empty availableSession variable. When a learner has a fulfilled entitlement for a course that doesn't have an enrollment ending, there should not be an empty availableSession variable. NOTE: We commented out the assertions to move this to the catalog utils test suite. """ # noAvailableSessions = "availableSessions: '[]'" # Test an enrollment end in the past mocked_course_overview = CourseOverviewFactory.create( start=self.TOMORROW, end=self.THREE_YEARS_FROM_NOW, self_paced=True, enrollment_end=self.THREE_YEARS_AGO ) mock_course_overview.return_value = mocked_course_overview course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=six.text_type(mocked_course_overview.id)) mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), 'enrollment_end': str(mocked_course_overview.enrollment_end), 'pacing_type': 'self_paced', 'type': 'verified', 'status': 'published' } ] CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment) # response = self.client.get(self.path) # self.assertIn(noAvailableSessions, response.content) # Test an enrollment end in the future sets an availableSession mocked_course_overview.enrollment_end = self.TOMORROW mocked_course_overview.save() mock_course_overview.return_value = mocked_course_overview mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), 'enrollment_end': str(mocked_course_overview.enrollment_end), 'pacing_type': 'self_paced', 'type': 'verified', 'status': 'published' } ] # response = self.client.get(self.path) # self.assertNotIn(noAvailableSessions, response.content) # Test an enrollment end that doesn't exist sets an availableSession mocked_course_overview.enrollment_end = None mocked_course_overview.save() mock_course_overview.return_value = mocked_course_overview mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), 'enrollment_end': None, 'pacing_type': 'self_paced', 'type': 'verified', 'status': 'published' } ]
def setUp(self): super(SplitTestPosition, self).setUp() self.student = UserFactory.create() CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) self.client.login(username=self.student.username, password='******')
def test_no_verified_enrollment(self): course = create_course_run(days_till_start=-1) user = create_user() CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.AUDIT) block = VerificationDeadlineDate(course, user) self.assertFalse(block.is_enabled)
def _enroll_users(self, mode): """Enroll users in the given mode.""" for user in self.users: CourseEnrollmentFactory(mode=mode, course_id=self.course.id, user=user)
def test_no_verification_deadline(self): course = create_course_run(days_till_start=-1, days_till_verification_deadline=None) user = self.create_user() CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) block = VerificationDeadlineDate(course, user) self.assertFalse(block.is_enabled)
def setUp(self): super(ContactUsViewTests, self).setUp() self.user = UserFactory() self.client.login(username=self.user.username, password='******') self.user_enrollment = CourseEnrollmentFactory.create(user=self.user, )
def test_upgrade_deadline_for_non_upgradeable_enrollment(self, mode): """ The property should return None if an upgrade cannot be upgraded. """ enrollment = CourseEnrollmentFactory(course_id=self.course.id, mode=mode) self.assertIsNone(enrollment.upgrade_deadline)
def create_student(self, username, email): student = UserFactory.create(username=username, email=email) CourseEnrollmentFactory.create(user=student, course_id=self.course.id) return student
def test_enabled_block_types(self, course_kwargs, user_kwargs, expected_blocks): course = create_course_run(**course_kwargs) user = create_user(**user_kwargs) CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) self.assert_block_types(course, user, expected_blocks)
def setUp(self): super(ContentGroupTestCase, self).setUp() self.course = CourseFactory.create( org='org', number='number', run='run', # This test needs to use a course that has already started -- # discussion topics only show up if the course has already started, # and the default start date for courses is Jan 1, 2030. start=datetime(2012, 2, 3, tzinfo=UTC), user_partitions=[ UserPartition( 0, 'Content Group Configuration', '', [Group(1, 'Alpha'), Group(2, 'Beta')], scheme_id='cohort') ], grading_policy={ "GRADER": [{ "type": "Homework", "min_count": 1, "drop_count": 0, "short_label": "HW", "weight": 1.0 }] }, cohort_config={'cohorted': True}, discussion_topics={}) self.staff_user = UserFactory.create(is_staff=True) self.alpha_user = UserFactory.create() self.beta_user = UserFactory.create() self.non_cohorted_user = UserFactory.create() for user in [ self.staff_user, self.alpha_user, self.beta_user, self.non_cohorted_user ]: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) alpha_cohort = CohortFactory(course_id=self.course.id, name='Cohort Alpha', users=[self.alpha_user]) beta_cohort = CohortFactory(course_id=self.course.id, name='Cohort Beta', users=[self.beta_user]) CourseUserGroupPartitionGroup.objects.create( course_user_group=alpha_cohort, partition_id=self.course.user_partitions[0].id, group_id=self.course.user_partitions[0].groups[0].id) CourseUserGroupPartitionGroup.objects.create( course_user_group=beta_cohort, partition_id=self.course.user_partitions[0].id, group_id=self.course.user_partitions[0].groups[1].id) self.alpha_module = ItemFactory.create( parent_location=self.course.location, category='discussion', discussion_id='alpha_group_discussion', discussion_target='Visible to Alpha', group_access={ self.course.user_partitions[0].id: [self.course.user_partitions[0].groups[0].id] }) self.beta_module = ItemFactory.create( parent_location=self.course.location, category='discussion', discussion_id='beta_group_discussion', discussion_target='Visible to Beta', group_access={ self.course.user_partitions[0].id: [self.course.user_partitions[0].groups[1].id] }) self.global_module = ItemFactory.create( parent_location=self.course.location, category='discussion', discussion_id='global_group_discussion', discussion_target='Visible to Everyone') self.course = self.store.get_item(self.course.location)
def test_enabled_block_types_with_non_upgradeable_course_run(self): course = create_course_run(days_till_start=-10, days_till_verification_deadline=None) user = create_user() CourseMode.objects.get(course_id=course.id, mode_slug=CourseMode.VERIFIED).delete() CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.AUDIT) self.assert_block_types(course, user, (TodaysDate, CourseEndDate))
def setUp(self): """ Set up a course with graded problems within a split test. Course hierarchy is as follows (modeled after how split tests are created in studio): -> course -> chapter -> sequential (graded) -> vertical -> split_test -> vertical (Group A) -> problem -> vertical (Group B) -> problem """ super(TestConditionalContent, self).setUp() # Create user partitions self.user_partition_group_a = 0 self.user_partition_group_b = 1 self.partition = UserPartition( 0, 'first_partition', 'First Partition', [ Group(self.user_partition_group_a, 'Group A'), Group(self.user_partition_group_b, 'Group B') ]) # Create course with group configurations and grading policy self.course = CourseFactory.create(user_partitions=[self.partition], grading_policy={ "GRADER": [{ "type": "Homework", "min_count": 1, "drop_count": 0, "short_label": "HW", "weight": 1.0 }] }) chapter = ItemFactory.create(parent_location=self.course.location, display_name='Chapter') # add a sequence to the course to which the problems can be added self.problem_section = ItemFactory.create( parent_location=chapter.location, category='sequential', metadata={ 'graded': True, 'format': 'Homework' }, display_name=self.TEST_SECTION_NAME) # Create users and partition them self.student_a = UserFactory.create( username='******', email='student_a@contrived_example.com') CourseEnrollmentFactory.create(user=self.student_a, course_id=self.course.id) self.student_b = UserFactory.create( username='******', email='student_b@contrived_example.com') CourseEnrollmentFactory.create(user=self.student_b, course_id=self.course.id) UserCourseTagFactory( user=self.student_a, course_id=self.course.id, key='xblock.partition_service.partition_{0}'.format( self.partition.id), value=str(self.user_partition_group_a)) UserCourseTagFactory( user=self.student_b, course_id=self.course.id, key='xblock.partition_service.partition_{0}'.format( self.partition.id), value=str(self.user_partition_group_b)) # Create a vertical to contain our split test problem_vertical = ItemFactory.create( parent_location=self.problem_section.location, category='vertical', display_name='Problem Unit') # Create the split test and child vertical containers vertical_a_url = self.course.id.make_usage_key( 'vertical', 'split_test_vertical_a') vertical_b_url = self.course.id.make_usage_key( 'vertical', 'split_test_vertical_b') self.split_test = ItemFactory.create( parent_location=problem_vertical.location, category='split_test', display_name='Split Test', user_partition_id=self.partition.id, group_id_to_child={ str(index): url for index, url in enumerate([vertical_a_url, vertical_b_url]) }) self.vertical_a = ItemFactory.create( parent_location=self.split_test.location, category='vertical', display_name='Group A problem container', location=vertical_a_url) self.vertical_b = ItemFactory.create( parent_location=self.split_test.location, category='vertical', display_name='Group B problem container', location=vertical_b_url)
def _create_enrollments(self, *course_ids): """Variadic helper used to create course enrollments.""" for course_id in course_ids: CourseEnrollmentFactory(user=self.user, course_id=course_id)
def test_unfulfilled_entitlement(self, mock_course_overview, mock_pseudo_session, mock_course_runs, mock_get_programs): """ When a learner has an unfulfilled entitlement, their course dashboard should have: - a hidden 'View Course' button - the text 'In order to view the course you must select a session:' - an unhidden course-entitlement-selection-container - a related programs message """ program = ProgramFactory() CourseEntitlementFactory.create( user=self.user, course_uuid=program['courses'][0]['uuid']) mock_get_programs.return_value = [program] course_key = CourseKey.from_string('course-v1:FAKE+FA1-MA1.X+3T2017') mock_course_overview.return_value = CourseOverviewFactory.create( start=self.TOMORROW, id=course_key) mock_course_runs.return_value = [{ 'key': six.text_type(course_key), 'enrollment_end': str(self.TOMORROW), 'pacing_type': 'instructor_paced', 'type': 'verified', 'status': 'published' }] mock_pseudo_session.return_value = { 'key': six.text_type(course_key), 'type': 'verified' } response = self.client.get(self.path) self.assertContains(response, 'class="course-target-link enter-course hidden"') self.assertContains(response, 'You must select a session to access the course.') self.assertContains( response, '<div class="course-entitlement-selection-container ">') self.assertContains(response, 'Related Programs:') # If an entitlement has already been redeemed by the user for a course run, do not let the run be selectable enrollment = CourseEnrollmentFactory( user=self.user, course_id=six.text_type(mock_course_overview.return_value.id), mode=CourseMode.VERIFIED) CourseEntitlementFactory.create( user=self.user, course_uuid=program['courses'][0]['uuid'], enrollment_course_run=enrollment) mock_course_runs.return_value = [{ 'key': 'course-v1:edX+toy+2012_Fall', 'enrollment_end': str(self.TOMORROW), 'pacing_type': 'instructor_paced', 'type': 'verified', 'status': 'published' }] response = self.client.get(self.path) # There should be two entitlements on the course page, one prompting for a mandatory session, but no # select option for the courses as there is only the single course run which has already been redeemed self.assertContains(response, '<li class="course-item">', count=2) self.assertContains(response, 'You must select a session to access the course.') self.assertNotContains(response, 'To access the course, select a session.')