Exemplo n.º 1
0
    def test_course_messaging(self):
        """
        Ensure that the following four use cases work as expected

        1) Anonymous users are shown a course message linking them to the login page
        2) Unenrolled users are shown a course message allowing them to enroll
        3) Enrolled users who show up on the course page after the course has begun
        are not shown a course message.
        4) Enrolled users who show up on the course page after the course has begun will
        see the course expiration banner if course duration limits are on for the course.
        5) Enrolled users who show up on the course page before the course begins
        are shown a message explaining when the course starts as well as a call to
        action button that allows them to add a calendar event.
        """
        # Verify that anonymous users are shown a login link in the course message
        url = course_home_url(self.course)
        response = self.client.get(url)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE_ANONYMOUS)

        # Verify that unenrolled users are shown an enroll call to action message
        user = self.create_user_for_course(self.course,
                                           CourseUserType.UNENROLLED)
        url = course_home_url(self.course)
        response = self.client.get(url)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE_UNENROLLED)

        # Verify that enrolled users are not shown any state warning message when enrolled and course has begun.
        CourseEnrollment.enroll(user, self.course.id)
        url = course_home_url(self.course)
        response = self.client.get(url)
        self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_ANONYMOUS)
        self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_UNENROLLED)
        self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_PRE_START)

        # Verify that enrolled users are shown the course expiration banner if content gating is enabled
        with override_waffle_flag(CONTENT_TYPE_GATING_FLAG, True):
            url = course_home_url(self.course)
            response = self.client.get(url)
            bannerText = get_expiration_banner_text(user, self.course)
            self.assertContains(response, bannerText, html=True)

        # Verify that enrolled users are not shown the course expiration banner if content gating is disabled
        with override_waffle_flag(CONTENT_TYPE_GATING_FLAG, False):
            url = course_home_url(self.course)
            response = self.client.get(url)
            bannerText = get_expiration_banner_text(user, self.course)
            self.assertNotContains(response, bannerText, html=True)

        # Verify that enrolled users are shown 'days until start' message before start date
        future_course = self.create_future_course()
        CourseEnrollment.enroll(user, future_course.id)
        url = course_home_url(future_course)
        response = self.client.get(url)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE)
        self.assertContains(response, TEST_COURSE_HOME_MESSAGE_PRE_START)
Exemplo n.º 2
0
 def test_course_no_enrollments(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.empty_course.id)
         )
         self._assert_empty_response(resp)
Exemplo n.º 3
0
 def test_user_not_enrolled(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.empty_course.id, username=self.student.username)
         )
         self.assertEqual(status.HTTP_404_NOT_FOUND, resp.status_code)
Exemplo n.º 4
0
 def test_user_does_not_exist(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.course.id, username='******')
         )
         self.assertEqual(status.HTTP_404_NOT_FOUND, resp.status_code)
Exemplo n.º 5
0
    def test_gradebook_data_filter_username_contains(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.return_value = self.mock_course_grade(
                self.other_student, passed=True, letter_grade='A', percent=0.85
            )

            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id, username_contains='other')
                )
                expected_results = [
                    OrderedDict([
                        ('course_id', text_type(self.course.id)),
                        ('email', self.other_student.email),
                        ('user_id', self.other_student.id),
                        ('username', self.other_student.username),
                        ('full_name', self.other_student.get_full_name()),
                        ('passed', True),
                        ('percent', 0.85),
                        ('letter_grade', 'A'),
                        ('progress_page_url', reverse(
                            'student_progress',
                            kwargs=dict(course_id=text_type(self.course.id), student_id=self.other_student.id)
                        )),
                        ('section_breakdown', self.expected_subsection_grades(letter_grade='A')),
                    ]),
                ]

                self.assertEqual(status.HTTP_200_OK, resp.status_code)
                actual_data = dict(resp.data)
                self.assertIsNone(actual_data['next'])
                self.assertIsNone(actual_data['previous'])
                self.assertEqual(expected_results, actual_data['results'])
Exemplo n.º 6
0
 def test_user_does_not_exist(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.course.id,
                          username='******'))
         self.assertEqual(status.HTTP_404_NOT_FOUND, resp.status_code)
Exemplo n.º 7
0
    def test_invalid_usage_key(self):
        with override_waffle_flag(self.waffle_flag, active=True):
            self.login_staff()
            post_data = [
                {
                    'user_id': self.student.id,
                    'usage_id': 'not-a-valid-usage-key',
                    'grade': {},  # doesn't matter what we put here.
                }
            ]

            resp = self.client.post(
                self.get_url(),
                data=json.dumps(post_data),
                content_type='application/json',
            )

            expected_data = [
                {
                    'user_id': self.student.id,
                    'usage_id': 'not-a-valid-usage-key',
                    'success': False,
                    'reason': "<class 'opaque_keys.edx.locator.BlockUsageLocator'>: not-a-valid-usage-key",
                },
            ]
            self.assertEqual(status.HTTP_422_UNPROCESSABLE_ENTITY, resp.status_code)
            self.assertEqual(expected_data, resp.data)
Exemplo n.º 8
0
 def test_feature_not_enabled(self):
     self.client.login(username=self.global_staff.username,
                       password=self.password)
     with override_waffle_flag(self.waffle_flag, active=False):
         resp = self.client.get(
             self.get_url(course_key=self.empty_course.id))
         self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
Exemplo n.º 9
0
    def test_user_does_not_exist(self):
        with override_waffle_flag(self.waffle_flag, active=True):
            self.login_staff()
            post_data = [{
                'user_id':
                -123,
                'usage_id':
                text_type(
                    self.subsections[self.chapter_1.location][0].location),
                'grade': {},  # doesn't matter what we put here.
            }]

            resp = self.client.post(
                self.get_url(),
                data=json.dumps(post_data),
                content_type='application/json',
            )

            expected_data = [
                {
                    'user_id':
                    -123,
                    'usage_id':
                    text_type(
                        self.subsections[self.chapter_1.location][0].location),
                    'success':
                    False,
                    'reason':
                    'User matching query does not exist.',
                },
            ]
            self.assertEqual(status.HTTP_422_UNPROCESSABLE_ENTITY,
                             resp.status_code)
            self.assertEqual(expected_data, resp.data)
Exemplo n.º 10
0
    def test_invalid_usage_key(self):
        with override_waffle_flag(self.waffle_flag, active=True):
            self.login_staff()
            post_data = [{
                'user_id': self.student.id,
                'usage_id': 'not-a-valid-usage-key',
                'grade': {},  # doesn't matter what we put here.
            }]

            resp = self.client.post(
                self.get_url(),
                data=json.dumps(post_data),
                content_type='application/json',
            )

            expected_data = [
                {
                    'user_id':
                    self.student.id,
                    'usage_id':
                    'not-a-valid-usage-key',
                    'success':
                    False,
                    'reason':
                    "<class 'opaque_keys.edx.locator.BlockUsageLocator'>: not-a-valid-usage-key",
                },
            ]
            self.assertEqual(status.HTTP_422_UNPROCESSABLE_ENTITY,
                             resp.status_code)
            self.assertEqual(expected_data, resp.data)
Exemplo n.º 11
0
 def test_video_urls_rewrite(self, waffle_flag_value, video_data_patch):
     """
     Verify the video blocks returned have their URL re-written for
     encoded videos.
     """
     video_data_patch.return_value = {
         'encoded_videos': {
             'hls': {
                 'url': 'https://xyz123.cloudfront.net/XYZ123ABC.mp4',
                 'file_size': 0
             },
             'mobile_low': {
                 'url': 'https://1234abcd.cloudfront.net/ABCD1234abcd.mp4',
                 'file_size': 0
             }
         }
     }
     with override_waffle_flag(ENABLE_VIDEO_URL_REWRITE, waffle_flag_value):
         blocks = get_blocks(self.request,
                             self.course.location,
                             requested_fields=['student_view_data'],
                             student_view_data=['video'])
     video_block_key = str(
         self.course.id.make_usage_key('video', 'sample_video'))
     video_block_data = blocks['blocks'][video_block_key]
     for video_data in six.itervalues(
             video_block_data['student_view_data']['encoded_videos']):
         if waffle_flag_value:
             self.assertNotIn('cloudfront', video_data['url'])
         else:
             self.assertIn('cloudfront', video_data['url'])
Exemplo n.º 12
0
    def test_subsection_does_not_exist(self):
        """
        When trying to override a grade for a valid usage key that does not exist in the requested course,
        we should get an error reason specifying that the key does not exist in the course.
        """
        with override_waffle_flag(self.waffle_flag, active=True):
            self.login_staff()
            usage_id = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@workflow'
            post_data = [
                {
                    'user_id': self.student.id,
                    'usage_id': usage_id,
                    'grade': {},  # doesn't matter what we put here.
                }
            ]

            resp = self.client.post(
                self.get_url(),
                data=json.dumps(post_data),
                content_type='application/json',
            )

            expected_data = [
                {
                    'user_id': self.student.id,
                    'usage_id': usage_id,
                    'success': False,
                    'reason': 'usage_key {} does not exist in this course.'.format(usage_id),
                },
            ]
            self.assertEqual(status.HTTP_422_UNPROCESSABLE_ENTITY, resp.status_code)
            self.assertEqual(expected_data, resp.data)
Exemplo n.º 13
0
    def test_user_does_not_exist(self):
        with override_waffle_flag(self.waffle_flag, active=True):
            self.login_staff()
            post_data = [
                {
                    'user_id': -123,
                    'usage_id': text_type(self.subsections[self.chapter_1.location][0].location),
                    'grade': {},  # doesn't matter what we put here.
                }
            ]

            resp = self.client.post(
                self.get_url(),
                data=json.dumps(post_data),
                content_type='application/json',
            )

            expected_data = [
                {
                    'user_id': -123,
                    'usage_id': text_type(self.subsections[self.chapter_1.location][0].location),
                    'success': False,
                    'reason': 'User matching query does not exist.',
                },
            ]
            self.assertEqual(status.HTTP_422_UNPROCESSABLE_ENTITY, resp.status_code)
            self.assertEqual(expected_data, resp.data)
Exemplo n.º 14
0
 def test_user_not_enrolled(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.empty_course.id,
                          username=self.student.username))
         self.assertEqual(status.HTTP_404_NOT_FOUND, resp.status_code)
Exemplo n.º 15
0
 def test_course_does_not_exist(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.post(
             self.get_url(course_key='course-v1:MITx+8.MechCX+2014_T1')
         )
         self.assertEqual(status.HTTP_404_NOT_FOUND, resp.status_code)
Exemplo n.º 16
0
    def test_page_size_parameter(self, page_size):
        user_size = 60
        with patch(
            'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read'
        ) as mock_grade:
            users = UserFactory.create_batch(user_size)
            mocked_course_grades = []
            for user in users:
                self._create_user_enrollments(user)
                mocked_course_grades.append(self.mock_course_grade(user, passed=True, letter_grade='A', percent=0.85))

            mock_grade.side_effect = mocked_course_grades

            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                query = ''
                if page_size:
                    query = '?page_size={}'.format(page_size)
                resp = self.client.get(
                    self.get_url(course_key=self.course.id) + query
                )
                self.assertEqual(status.HTTP_200_OK, resp.status_code)
                actual_data = dict(resp.data)
                expected_page_size = page_size or CourseEnrollmentPagination.page_size
                if expected_page_size > user_size:
                    expected_page_size = user_size
                self.assertEqual(len(actual_data['results']), expected_page_size)
Exemplo n.º 17
0
 def test_feature_not_enabled(self):
     self.client.login(username=self.global_staff.username, password=self.password)
     with override_waffle_flag(self.waffle_flag, active=False):
         resp = self.client.post(
             self.get_url(course_key=self.empty_course.id)
         )
         self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
Exemplo n.º 18
0
    def test_home_page(
        self,
        enable_unenrolled_access,
        course_visibility,
        user_type,
        expected_enroll_message,
        expected_course_outline,
    ):
        self.create_user_for_course(self.course, user_type)

        # Render the course home page
        with mock.patch(
                'xmodule.course_module.CourseDescriptor.course_visibility',
                course_visibility):
            # Test access with anonymous flag and course visibility
            with override_waffle_flag(COURSE_ENABLE_UNENROLLED_ACCESS_FLAG,
                                      enable_unenrolled_access):
                url = course_home_url(self.course)
                response = self.client.get(url)

        # Verify that the course tools and dates are always shown
        self.assertContains(response, TEST_COURSE_TOOLS)
        self.assertContains(response, TEST_COURSE_TODAY)

        is_anonymous = user_type is CourseUserType.ANONYMOUS
        is_enrolled = user_type is CourseUserType.ENROLLED
        is_enrolled_or_staff = is_enrolled or user_type in (
            CourseUserType.UNENROLLED_STAFF, CourseUserType.GLOBAL_STAFF)

        self.assertContains(response,
                            'Learn About Verified Certificate',
                            count=(1 if is_enrolled else 0))

        # Verify that start button, course sock, and welcome message
        # are only shown to enrolled users or staff.
        self.assertContains(response,
                            'Start Course',
                            count=(1 if is_enrolled_or_staff else 0))
        self.assertContains(response,
                            TEST_WELCOME_MESSAGE,
                            count=(1 if is_enrolled_or_staff else 0))

        # Verify the outline is shown to enrolled users, unenrolled_staff and anonymous users if allowed
        self.assertContains(response,
                            TEST_CHAPTER_NAME,
                            count=(1 if expected_course_outline else 0))

        # Verify that the expected message is shown to the user
        if not enable_unenrolled_access or course_visibility != COURSE_VISIBILITY_PUBLIC:
            self.assertContains(response,
                                'To see course content',
                                count=(1 if is_anonymous else 0))
            self.assertContains(response,
                                '<div class="user-messages"',
                                count=(1 if expected_enroll_message else 0))
            if expected_enroll_message:
                self.assertContains(
                    response,
                    'You must be enrolled in the course to see course content.'
                )
Exemplo n.º 19
0
    def test_redirect_view(self):
        profile_url = "http://profile-spa/abc/"
        with override_settings(PROFILE_MICROFRONTEND_URL=profile_url):
            with override_waffle_flag(REDIRECT_TO_PROFILE_MICROFRONTEND,
                                      active=True):
                profile_path = reverse('learner_profile',
                                       kwargs={'username': self.USERNAME})

                # Test with waffle flag active, site setting disabled
                response = self.client.get(path=profile_path)
                for attribute in self.CONTEXT_DATA:
                    self.assertIn(attribute, response.content)

                # Test with waffle flag active, site setting enabled
                site_domain = 'othersite.example.com'
                self.set_up_site(site_domain, {
                    'SITE_NAME': site_domain,
                    'ENABLE_PROFILE_MICROFRONTEND': True
                })
                self.client.login(username=self.USERNAME,
                                  password=self.PASSWORD)
                response = self.client.get(path=profile_path)
                self.assertRedirects(response,
                                     profile_url + self.USERNAME,
                                     target_status_code=404)
Exemplo n.º 20
0
 def test_visual_progress_happy_path_visual_switch_disabled(self):
     self._make_site_config(True)
     with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True):
         with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS,
                                       False):
             with override_waffle_flag(waffle.waffle_flag(), active=True):
                 assert waffle.visual_progress_enabled(
                     self.course_key) is True
Exemplo n.º 21
0
    def override(self, active=True):
        """
        Shortcut method for `override_waffle_flag`.
        """
        # TODO We can move this import to the top of the file once this code is
        # not all contained within the __init__ module.
        from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag

        with override_waffle_flag(self, active):
            yield
    def test_staff_can_see_writable_gradebook(self):
        """
        Test that, when the writable gradebook featue is enabled, a staff member can see it.
        """
        waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK]
        with override_waffle_flag(waffle_flag, active=True):
            response = self.client.get(self.url)

        expected_gradebook_url = 'http://gradebook.local.edx.org/{}'.format(self.course.id)
        self.assertIn(expected_gradebook_url, response.content)
        self.assertIn('View Gradebook', response.content)
Exemplo n.º 23
0
    def test_filter_cohort_id_does_not_exist(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.return_value = self.mock_course_grade(self.student, passed=True, letter_grade='A', percent=0.85)

            empty_cohort = CohortFactory(course_id=self.course.id, name="TestCohort", users=[])
            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id) + '?cohort_id={}'.format(empty_cohort.id)
                )
                self._assert_empty_response(resp)
Exemplo n.º 24
0
    def test_gradebook_data_filter_username_contains_no_match(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.return_value = self.mock_course_grade(
                self.other_student, passed=True, letter_grade='A', percent=0.85
            )

            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id, username_contains='fooooooooooooooooo')
                )
                self._assert_empty_response(resp)
Exemplo n.º 25
0
 def test_course_no_enrollments(self):
     with override_waffle_flag(self.waffle_flag, active=True):
         self.login_staff()
         resp = self.client.get(
             self.get_url(course_key=self.empty_course.id))
         expected_data = {
             'next': None,
             'previous': None,
             'results': [],
         }
         self.assertEqual(status.HTTP_200_OK, resp.status_code)
         self.assertEqual(expected_data, dict(resp.data))
Exemplo n.º 26
0
    def test_home_page(self, enable_unenrolled_access, course_visibility,
                       user_type, expected_message):
        self.create_user_for_course(self.course, user_type)

        # Render the course home page
        with mock.patch(
                'xmodule.course_module.CourseDescriptor.course_visibility',
                course_visibility):
            # Test access with anonymous flag and course visibility
            with override_waffle_flag(COURSE_ENABLE_UNENROLLED_ACCESS_FLAG,
                                      enable_unenrolled_access):
                url = course_home_url(self.course)
                response = self.client.get(url)

        # Verify that the course tools and dates are always shown
        self.assertContains(response, 'Course Tools')
        self.assertContains(response, 'Today is')

        # Verify that start button, course sock, and welcome message
        # are only shown to enrolled users.
        is_enrolled = user_type is CourseUserType.ENROLLED
        is_unenrolled_staff = user_type is CourseUserType.UNENROLLED_STAFF
        expected_welcome = 1 if (is_enrolled or is_unenrolled_staff) else 0
        self.assertContains(response, 'Start Course', count=expected_welcome)
        self.assertContains(response,
                            'Learn About Verified Certificate',
                            count=(1 if is_enrolled else 0))
        self.assertContains(response,
                            TEST_WELCOME_MESSAGE,
                            count=expected_welcome)

        # Verify the outline is shown to enrolled users, unenrolled_staff and anonymous users if allowed
        is_public = course_visibility == COURSE_VISIBILITY_PUBLIC and enable_unenrolled_access
        is_public_outline = course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE and enable_unenrolled_access
        expected_chapter = 1 if (is_public
                                 or is_public_outline) else expected_welcome
        self.assertContains(response,
                            TEST_CHAPTER_NAME,
                            count=expected_chapter)

        # Verify that the expected message is shown to the user
        self.assertContains(
            response,
            'To see course content',
            count=1 if user_type is CourseUserType.ANONYMOUS else 0)
        self.assertContains(response,
                            '<div class="user-messages">',
                            count=1 if expected_message else 0)
        if expected_message:
            self.assertContains(
                response,
                'You must be enrolled in the course to see course content.')
Exemplo n.º 27
0
    def test_gradebook_data_for_course(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.side_effect = [
                self.mock_course_grade(self.student, passed=True, letter_grade='A', percent=0.85),
                self.mock_course_grade(self.other_student, passed=False, letter_grade=None, percent=0.45),
            ]

            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id)
                )
                self._assert_data_all_users(resp)
Exemplo n.º 28
0
    def test_filter_enrollment_mode_no_students(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.side_effect = [
                self.mock_course_grade(self.student, passed=True, letter_grade='A', percent=0.85),
                self.mock_course_grade(self.other_student, passed=False, letter_grade=None, percent=0.45),
            ]

            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id) + '?enrollment_mode={}'.format(CourseMode.VERIFIED)
                )
                self._assert_empty_response(resp)
Exemplo n.º 29
0
    def test_timed_exam_gating_waffle_flag(self, mocked_user):
        """
        Verify the code inside the waffle flag is not executed with the flag off
        Verify the code inside the waffle flag is executed with the flag on
        """
        # the order of the overrides is important since the `assert_not_called` does
        # not appear to be limited to just the override_waffle_flag = False scope
        with override_waffle_flag(TIMED_EXAM_GATING_WAFFLE_FLAG, active=False):
            self._get_rendered_view(self.sequence_5_1,
                                    extra_context=dict(
                                        next_url='NextSequential',
                                        prev_url='PrevSequential'),
                                    view=STUDENT_VIEW)
            mocked_user.assert_not_called()

        with override_waffle_flag(TIMED_EXAM_GATING_WAFFLE_FLAG, active=True):
            self._get_rendered_view(self.sequence_5_1,
                                    extra_context=dict(
                                        next_url='NextSequential',
                                        prev_url='PrevSequential'),
                                    view=STUDENT_VIEW)
            mocked_user.assert_called_once()
Exemplo n.º 30
0
 def test_no_gradebook_learner_count_message(self):
     """
     Test that, when the writable gradebook featue IS enabled, there is NOT
     a message that the feature is only available for courses with small
     numbers of learners.
     """
     waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK]
     with override_waffle_flag(waffle_flag, active=True):
         response = self.client.get(self.url)
     self.assertNotIn(
         TestInstructorDashboard.GRADEBOOK_LEARNER_COUNT_MESSAGE,
         response.content)
     self.assertIn('View Gradebook', response.content)
Exemplo n.º 31
0
 def test_about_page_public_view(self, course_visibility):
     """
     Assert that anonymous or unenrolled users see View Course option
     when unenrolled access flag is set
     """
     with mock.patch('xmodule.course_module.CourseDescriptor.course_visibility', course_visibility):
         with override_waffle_flag(COURSE_ENABLE_UNENROLLED_ACCESS_FLAG, active=True):
             url = reverse('about_course', args=[text_type(self.course.id)])
             resp = self.client.get(url)
     if course_visibility == COURSE_VISIBILITY_PUBLIC or course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE:
         self.assertContains(resp, "View Course")
     else:
         self.assertContains(resp, "Enroll Now")
Exemplo n.º 32
0
 def test_no_gradebook_learner_count_message(self):
     """
     Test that, when the writable gradebook featue IS enabled, there is NOT
     a message that the feature is only available for courses with small
     numbers of learners.
     """
     waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK]
     with override_waffle_flag(waffle_flag, active=True):
         response = self.client.get(self.url)
     self.assertNotIn(
         TestInstructorDashboard.GRADEBOOK_LEARNER_COUNT_MESSAGE,
         response.content
     )
     self.assertIn('View Gradebook', response.content)
Exemplo n.º 33
0
 def test_about_page_public_view(self, course_visibility):
     """
     Assert that anonymous or unenrolled users see View Course option
     when unenrolled access flag is set
     """
     with mock.patch('xmodule.course_module.CourseDescriptor.course_visibility', course_visibility):
         with override_waffle_flag(COURSE_ENABLE_UNENROLLED_ACCESS_FLAG, active=True):
             url = reverse('about_course', args=[text_type(self.course.id)])
             resp = self.client.get(url)
     self.assertEqual(resp.status_code, 200)
     if course_visibility == COURSE_VISIBILITY_PUBLIC or course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE:
         self.assertIn("View Course", resp.content)
     else:
         self.assertIn("Enroll in", resp.content)
Exemplo n.º 34
0
    def test_home_page(
            self, enable_unenrolled_access, course_visibility, user_type,
            expected_enroll_message, expected_course_outline,
    ):
        self.create_user_for_course(self.course, user_type)

        # Render the course home page
        with mock.patch('xmodule.course_module.CourseDescriptor.course_visibility', course_visibility):
            # Test access with anonymous flag and course visibility
            with override_waffle_flag(COURSE_ENABLE_UNENROLLED_ACCESS_FLAG, enable_unenrolled_access):
                url = course_home_url(self.course)
                response = self.client.get(url)

                private_url = course_home_url(self.private_course)
                private_response = self.client.get(private_url)

        # Verify that the course tools and dates are always shown
        self.assertContains(response, TEST_COURSE_TOOLS)
        self.assertContains(response, TEST_COURSE_TODAY)

        is_anonymous = user_type is CourseUserType.ANONYMOUS
        is_enrolled = user_type is CourseUserType.ENROLLED
        is_enrolled_or_staff = is_enrolled or user_type in (
            CourseUserType.UNENROLLED_STAFF, CourseUserType.GLOBAL_STAFF
        )

        self.assertContains(response, 'Learn About Verified Certificate', count=(1 if is_enrolled else 0))

        # Verify that start button, course sock, and welcome message
        # are only shown to enrolled users or staff.
        self.assertContains(response, 'Start Course', count=(1 if is_enrolled_or_staff else 0))
        self.assertContains(response, TEST_WELCOME_MESSAGE, count=(1 if is_enrolled_or_staff else 0))

        # Verify the outline is shown to enrolled users, unenrolled_staff and anonymous users if allowed
        self.assertContains(response, TEST_CHAPTER_NAME, count=(1 if expected_course_outline else 0))

        # Verify the message shown to the user
        if not enable_unenrolled_access or course_visibility != COURSE_VISIBILITY_PUBLIC:
            self.assertContains(
                response, 'To see course content', count=(1 if is_anonymous else 0)
            )
            self.assertContains(response, '<div class="user-messages"', count=(1 if expected_enroll_message else 0))
            if expected_enroll_message:
                self.assertContains(response, 'You must be enrolled in the course to see course content.')

        if enable_unenrolled_access and course_visibility == COURSE_VISIBILITY_PUBLIC:
            if user_type == CourseUserType.UNENROLLED and self.private_course.invitation_only:
                if expected_enroll_message:
                    self.assertContains(private_response,
                                        'You must be enrolled in the course to see course content.')
Exemplo n.º 35
0
    def test_logistration_mfe_redirects(self, url_name, path):
        """
        Test that if Logistration MFE is enabled, then we redirect to
        the correct URL.
        """
        site_domain = 'example.org'
        self.set_up_site(site_domain, {'ENABLE_ACCOUNT_MICROFRONTEND': True})

        with override_waffle_flag(REDIRECT_TO_ACCOUNT_MICROFRONTEND,
                                  active=True):
            response = self.client.get(reverse(url_name))

        self.assertEqual(response.url,
                         settings.ACCOUNT_MICROFRONTEND_URL + path)
        self.assertEqual(response.status_code, 302)
Exemplo n.º 36
0
    def test_logistration_redirect_params(self, url_name, path, query_params):
        """
        Test that if request is redirected to logistration MFE,
        query params are passed to the redirect url.
        """
        site_domain = 'example.org'
        expected_url = settings.ACCOUNT_MICROFRONTEND_URL + path + '?' + urlencode(
            query_params)

        self.set_up_site(site_domain, {'ENABLE_ACCOUNT_MICROFRONTEND': True})

        with override_waffle_flag(REDIRECT_TO_ACCOUNT_MICROFRONTEND,
                                  active=True):
            response = self.client.get(reverse(url_name), query_params)

        self.assertRedirects(response, expected_url)
Exemplo n.º 37
0
    def test_recalculate_subsection_grade_v3(self, freeze_flag_value, end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() - timedelta(end_date_adjustment))
        for user in self.users:
            CourseEnrollment.enroll(user, self.course.id)

        with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
            modified_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=1)
            with patch('lms.djangoapps.grades.tasks._has_db_updated_with_new_score') as mock_has_db_updated:
                result = recalculate_subsection_grade_v3.apply_async(kwargs=self.recalculate_subsection_grade_kwargs)
                self._assert_for_freeze_grade_flag(
                    result,
                    freeze_flag_value,
                    end_date_adjustment,
                    mock_log,
                    mock_has_db_updated,
                    '_recalculate_subsection_grade'
                )
Exemplo n.º 38
0
    def test_compute_all_grades_for_course(self, freeze_flag_value,
                                           end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() -
                           timedelta(end_date_adjustment))
        for user in self.users:
            CourseEnrollment.enroll(user, self.course.id)

        with override_waffle_flag(self.freeze_grade_flag,
                                  active=freeze_flag_value):
            with patch(
                    'lms.djangoapps.grades.tasks.compute_grades_for_course_v2.apply_async',
                    return_value=None) as mock_compute_grades:
                result = compute_all_grades_for_course.apply_async(
                    kwargs={'course_key': six.text_type(self.course.id)})
                self._assert_for_freeze_grade_flag(
                    result, freeze_flag_value, end_date_adjustment, mock_log,
                    mock_compute_grades, 'compute_all_grades_for_course')
Exemplo n.º 39
0
    def test_redirect_view(self):
        with override_waffle_flag(REDIRECT_TO_ACCOUNT_MICROFRONTEND, active=True):
            old_url_path = reverse('account_settings')

            # Test with waffle flag active and site setting disabled, does not redirect
            response = self.client.get(path=old_url_path)
            for attribute in self.FIELDS:
                self.assertIn(attribute, response.content)

            # Test with waffle flag active and site setting enabled, redirects to microfrontend
            site_domain = 'othersite.example.com'
            self.set_up_site(site_domain, {
                'SITE_NAME': site_domain,
                'ENABLE_ACCOUNT_MICROFRONTEND': True
            })
            self.client.login(username=self.USERNAME, password=self.PASSWORD)
            response = self.client.get(path=old_url_path)
            self.assertRedirects(response, settings.ACCOUNT_MICROFRONTEND_URL, fetch_redirect_response=False)
Exemplo n.º 40
0
    def test_redirect_view(self):
        with override_waffle_flag(REDIRECT_TO_PROFILE_MICROFRONTEND, active=True):
            profile_path = reverse('learner_profile', kwargs={'username': self.USERNAME})

            # Test with waffle flag active and site setting disabled, does not redirect
            response = self.client.get(path=profile_path)
            for attribute in self.CONTEXT_DATA:
                self.assertIn(attribute, response.content)

            # Test with waffle flag active and site setting enabled, redirects to microfrontend
            site_domain = 'othersite.example.com'
            self.set_up_site(site_domain, {
                'SITE_NAME': site_domain,
                'ENABLE_PROFILE_MICROFRONTEND': True
            })
            self.client.login(username=self.USERNAME, password=self.PASSWORD)
            response = self.client.get(path=profile_path)
            profile_url = settings.PROFILE_MICROFRONTEND_URL
            self.assertRedirects(response, profile_url + self.USERNAME, fetch_redirect_response=False)
Exemplo n.º 41
0
    def test_recalculate_subsection_grade_v3(self, freeze_flag_value, end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() - timedelta(end_date_adjustment))
        for user in self.users:
            CourseEnrollment.enroll(user, self.course.id)

        with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
            modified_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=1)
            with patch(
                'lms.djangoapps.grades.tasks.GradesService',
                return_value=MockGradesService(mocked_return_value=MagicMock(modified=modified_datetime))
            ) as mock_grade_service:
                result = recalculate_subsection_grade_v3.apply_async(kwargs=self.recalculate_subsection_grade_kwargs)
                self._assert_for_freeze_grade_flag(
                    result,
                    freeze_flag_value,
                    end_date_adjustment,
                    mock_log,
                    mock_grade_service,
                    '_recalculate_subsection_grade'
                )
Exemplo n.º 42
0
    def test_recalculate_course_and_subsection_grades(self, freeze_flag_value, end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() - timedelta(end_date_adjustment))
        CourseEnrollment.enroll(self.user, self.course.id)
        with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
            with patch('lms.djangoapps.grades.tasks.CourseGradeFactory') as mock_factory:
                factory = mock_factory.return_value
                kwargs = {
                    'user_id': self.user.id,
                    'course_key': six.text_type(self.course.id),
                }

                result = tasks.recalculate_course_and_subsection_grades_for_user.apply_async(kwargs=kwargs)
                self._assert_for_freeze_grade_flag(
                    result,
                    freeze_flag_value,
                    end_date_adjustment,
                    mock_log,
                    factory.read,
                    'recalculate_course_and_subsection_grades_for_user'
                )
Exemplo n.º 43
0
    def test_redirect_view(self):
        profile_url = "http://profile-spa/abc/"
        with override_settings(PROFILE_MICROFRONTEND_URL=profile_url):
            with override_waffle_flag(REDIRECT_TO_PROFILE_MICROFRONTEND, active=True):
                profile_path = reverse('learner_profile', kwargs={'username': self.USERNAME})

                # Test with waffle flag active, site setting disabled
                response = self.client.get(path=profile_path)
                for attribute in self.CONTEXT_DATA:
                    self.assertIn(attribute, response.content)

                # Test with waffle flag active, site setting enabled
                site_domain = 'othersite.example.com'
                self.set_up_site(site_domain, {
                    'SITE_NAME': site_domain,
                    'ENABLE_PROFILE_MICROFRONTEND': True
                })
                self.client.login(username=self.USERNAME, password=self.PASSWORD)
                response = self.client.get(path=profile_path)
                self.assertRedirects(response, profile_url + self.USERNAME, target_status_code=404)
Exemplo n.º 44
0
    def test_grades_frozen(self):
        """
        Should receive a 403 when grades have been frozen for a course.
        """
        with patch('lms.djangoapps.grades.api.v1.views.are_grades_frozen', return_value=True):
            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                post_data = [
                    {
                        'user_id': self.student.id,
                        'usage_id': text_type(self.subsections[self.chapter_1.location][0].location),
                        'grade': {},  # doesn't matter what we put here.
                    }
                ]

                resp = self.client.post(
                    self.get_url(),
                    data=json.dumps(post_data),
                    content_type='application/json',
                )
                self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
Exemplo n.º 45
0
    def test_filter_enrollment_mode(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.side_effect = [
                self.mock_course_grade(self.student, passed=True, letter_grade='A', percent=0.85),
                self.mock_course_grade(self.other_student, passed=False, letter_grade=None, percent=0.45),
            ]

            # Enroll a verified student, for whom data should not be returned.
            verified_student = UserFactory()
            _ = CourseEnrollmentFactory(
                course_id=self.course.id,
                user=verified_student,
                created=datetime(2013, 1, 1, tzinfo=UTC),
                mode=CourseMode.VERIFIED,
            )
            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                resp = self.client.get(
                    self.get_url(course_key=self.course.id) + '?enrollment_mode={}'.format(CourseMode.AUDIT)
                )

                self._assert_data_all_users(resp)
Exemplo n.º 46
0
    def test_compute_all_grades_for_course(self, freeze_flag_value, end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() - timedelta(end_date_adjustment))
        for user in self.users:
            CourseEnrollment.enroll(user, self.course.id)

        with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
            with patch(
                'lms.djangoapps.grades.tasks.compute_grades_for_course_v2.apply_async',
                return_value=None
            ) as mock_compute_grades:
                result = compute_all_grades_for_course.apply_async(
                    kwargs={
                        'course_key': six.text_type(self.course.id)
                    }
                )
                self._assert_for_freeze_grade_flag(
                    result,
                    freeze_flag_value,
                    end_date_adjustment,
                    mock_log,
                    mock_compute_grades,
                    'compute_all_grades_for_course'
                )
Exemplo n.º 47
0
    def test_filter_cohort_id_and_enrollment_mode(self):
        with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade:
            mock_grade.return_value = self.mock_course_grade(self.student, passed=True, letter_grade='A', percent=0.85)

            cohort = CohortFactory(course_id=self.course.id, name="TestCohort", users=[self.student])
            with override_waffle_flag(self.waffle_flag, active=True):
                self.login_staff()
                # both of our test users are in the audit track, so this is functionally equivalent
                # to just `?cohort_id=cohort.id`.
                query = '?cohort_id={}&enrollment_mode={}'.format(cohort.id, CourseMode.AUDIT)
                resp = self.client.get(
                    self.get_url(course_key=self.course.id) + query
                )

                expected_results = [
                    OrderedDict([
                        ('course_id', text_type(self.course.id)),
                        ('email', self.student.email),
                        ('user_id', self.student.id),
                        ('username', self.student.username),
                        ('full_name', self.student.get_full_name()),
                        ('passed', True),
                        ('percent', 0.85),
                        ('letter_grade', 'A'),
                        ('progress_page_url', reverse(
                            'student_progress',
                            kwargs=dict(course_id=text_type(self.course.id), student_id=self.student.id)
                        )),
                        ('section_breakdown', self.expected_subsection_grades(letter_grade='A')),
                    ]),
                ]

                self.assertEqual(status.HTTP_200_OK, resp.status_code)
                actual_data = dict(resp.data)
                self.assertIsNone(actual_data['next'])
                self.assertIsNone(actual_data['previous'])
                self.assertEqual(expected_results, actual_data['results'])
Exemplo n.º 48
0
    def test_compute_grades_for_course(self, freeze_flag_value, end_date_adjustment, mock_log):
        self.set_up_course(course_end=timezone.now() - timedelta(end_date_adjustment))
        for user in self.users:
            CourseEnrollment.enroll(user, self.course.id)

        with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
            with patch('lms.djangoapps.grades.tasks.CourseGradeFactory') as mock_factory:
                factory = mock_factory.return_value
                with mock_get_score(1, 2):
                    result = compute_grades_for_course.apply_async(
                        kwargs={
                            'course_key': six.text_type(self.course.id),
                            'batch_size': 2,
                            'offset': 4,
                        }
                    )
                    self._assert_for_freeze_grade_flag(
                        result,
                        freeze_flag_value,
                        end_date_adjustment,
                        mock_log,
                        factory.iter,
                        'compute_grades_for_course'
                    )
Exemplo n.º 49
0
 def override(self, active=True):
     # TODO We can move this import to the top of the file once this code is
     # not all contained within the __init__ module.
     from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
     with override_waffle_flag(self, active):
         yield
Exemplo n.º 50
0
 def test_student(self):
     self.client.login(username=self.student.username, password=self.password)
     with override_waffle_flag(self.waffle_flag, active=True):
         resp = self.client.post(self.get_url())
         self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)