Exemple #1
0
    def test_course_updates_invalid_url(self):
        """
        Tests the error conditions for the invalid course updates URL.
        """
        # Testing the response code by passing slash separated course id whose format is valid but no course
        # having this id exists.
        invalid_course_key = f'{self.course.id}_blah_blah_blah'
        course_updates_url = reverse_course_url('course_info_handler',
                                                invalid_course_key)
        response = self.client.get(course_updates_url)
        self.assertEqual(response.status_code, 404)

        # Testing the response code by passing split course id whose format is valid but no course
        # having this id exists.
        split_course_key = CourseLocator(org='orgASD',
                                         course='course_01213',
                                         run='Run_0_hhh_hhh_hhh')
        course_updates_url_split = reverse_course_url('course_info_handler',
                                                      split_course_key)
        response = self.client.get(course_updates_url_split)
        self.assertEqual(response.status_code, 404)

        # Testing the response by passing split course id whose format is invalid.
        invalid_course_id = f'invalid.course.key/{split_course_key}'
        course_updates_url_split = reverse_course_url('course_info_handler',
                                                      invalid_course_id)
        response = self.client.get(course_updates_url_split)
        self.assertEqual(response.status_code, 404)
 def setUp(self):
     """
     Sets up the test course.
     """
     super(ExportTestCase, self).setUp()
     self.url = reverse_course_url('export_handler', self.course.id)
     self.status_url = reverse_course_url('export_status_handler', self.course.id)
 def setUp(self):
     """
     Sets up the test course.
     """
     super(ExportTestCase, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments
     self.url = reverse_course_url('export_handler', self.course.id)
     self.status_url = reverse_course_url('export_status_handler',
                                          self.course.id)
Exemple #4
0
    def test_json_responses(self):
        outline_url = reverse_course_url('course_handler', self.course.id)
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter', display_name="Week 1")
        lesson = ItemFactory.create(parent_location=chapter.location, category='sequential', display_name="Lesson 1")
        subsection = ItemFactory.create(
            parent_location=lesson.location,
            category='vertical',
            display_name='Subsection 1'
        )
        ItemFactory.create(parent_location=subsection.location, category="video", display_name="My Video")

        resp = self.client.get(outline_url, HTTP_ACCEPT='application/json')
        json_response = json.loads(resp.content.decode('utf-8'))

        # First spot check some values in the root response
        self.assertEqual(json_response['category'], 'course')
        self.assertEqual(json_response['id'], six.text_type(self.course.location))
        self.assertEqual(json_response['display_name'], self.course.display_name)
        self.assertTrue(json_response['published'])
        self.assertIsNone(json_response['visibility_state'])

        # Now verify the first child
        children = json_response['child_info']['children']
        self.assertGreater(len(children), 0)
        first_child_response = children[0]
        self.assertEqual(first_child_response['category'], 'chapter')
        self.assertEqual(first_child_response['id'], six.text_type(chapter.location))
        self.assertEqual(first_child_response['display_name'], 'Week 1')
        self.assertTrue(json_response['published'])
        self.assertEqual(first_child_response['visibility_state'], VisibilityState.unscheduled)
        self.assertGreater(len(first_child_response['child_info']['children']), 0)

        # Finally, validate the entire response for consistency
        self.assert_correct_json_response(json_response)
    def test_delete_image_type_asset(self):
        """ Tests deletion of image type asset """
        image_asset = self.get_sample_asset(self.asset_name, asset_type="image")
        thumbnail_image_asset = self.get_sample_asset('delete_test_thumbnail', asset_type="image")

        # upload image
        response = self.client.post(self.url, {"name": "delete_image_test", "file": image_asset})
        self.assertEqual(response.status_code, 200)
        uploaded_image_url = json.loads(response.content.decode('utf-8'))['asset']['url']

        # upload image thumbnail
        response = self.client.post(self.url, {"name": "delete_image_thumb_test", "file": thumbnail_image_asset})
        self.assertEqual(response.status_code, 200)
        thumbnail_url = json.loads(response.content.decode('utf-8'))['asset']['url']
        thumbnail_location = StaticContent.get_location_from_path(thumbnail_url)

        image_asset_location = AssetKey.from_string(uploaded_image_url)
        content = contentstore().find(image_asset_location)
        content.thumbnail_location = thumbnail_location
        contentstore().save(content)

        with mock.patch('opaque_keys.edx.locator.CourseLocator.make_asset_key') as mock_asset_key:
            mock_asset_key.return_value = thumbnail_location

            test_url = reverse_course_url(
                'assets_handler', self.course.id, kwargs={'asset_key_string': str(uploaded_image_url)})
            resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
            self.assertEqual(resp.status_code, 204)
Exemple #6
0
    def test_json_responses(self, is_concise):
        """
        Verify the JSON responses returned for the course.

        Arguments:
            is_concise (Boolean) : If True, fetch concise version of course outline.
        """
        outline_url = reverse_course_url('course_handler', self.course.id)
        outline_url = outline_url + '?format=concise' if is_concise else outline_url
        resp = self.client.get(outline_url, HTTP_ACCEPT='application/json')
        json_response = json.loads(resp.content.decode('utf-8'))

        # First spot check some values in the root response
        self.assertEqual(json_response['category'], 'course')
        self.assertEqual(json_response['id'], six.text_type(self.course.location))
        self.assertEqual(json_response['display_name'], self.course.display_name)
        self.assertNotEqual(json_response.get('published', False), is_concise)
        self.assertIsNone(json_response.get('visibility_state'))

        # Now verify the first child
        children = json_response['child_info']['children']
        self.assertGreater(len(children), 0)
        first_child_response = children[0]
        self.assertEqual(first_child_response['category'], 'chapter')
        self.assertEqual(first_child_response['id'], six.text_type(self.chapter.location))
        self.assertEqual(first_child_response['display_name'], 'Week 1')
        self.assertNotEqual(json_response.get('published', False), is_concise)
        if not is_concise:
            self.assertEqual(first_child_response['visibility_state'], VisibilityState.unscheduled)
        self.assertGreater(len(first_child_response['child_info']['children']), 0)

        # Finally, validate the entire response for consistency
        self.assert_correct_json_response(json_response, is_concise)
Exemple #7
0
 def create_update_url(self, provided_id=None, course_key=None):
     if course_key is None:
         course_key = self.course.id
     kwargs = {'provided_id': str(provided_id)} if provided_id else None
     return reverse_course_url('course_info_update_handler',
                               course_key,
                               kwargs=kwargs)
Exemple #8
0
 def setUp(self):
     super(CreditEligibilityTest, self).setUp()
     self.course = CourseFactory.create(org='edX',
                                        number='dummy',
                                        display_name='Credit Course')
     self.course_details_url = reverse_course_url(
         'settings_handler', six.text_type(self.course.id))
    def test_exam_settings_alert_with_exam_settings_disabled(
            self, page_handler):
        """
        An alert should appear if current exam settings are invalid.
        The exam settings alert should direct users to the advanced settings page
        if the exam settings feature is not available.
        """
        # create an error by setting proctortrack as the provider and not setting
        # the (required) escalation contact
        self.course.proctoring_provider = 'proctortrack'
        self.course.enable_proctored_exams = True
        self.save_course()

        url = reverse_course_url(page_handler, self.course.id)
        resp = self.client.get(url, HTTP_ACCEPT='text/html')
        alert_text = self._get_exam_settings_alert_text(resp.content)
        assert (
            'This course has proctored exam settings that are incomplete or invalid.'
            in alert_text)
        self.maxDiff = None
        if page_handler == 'advanced_settings_handler':
            assert (
                'You will be unable to make changes until the following settings are updated on the page below.'
                in alert_text)
        else:
            assert 'To update these settings go to the Advanced Settings page.' in alert_text
Exemple #10
0
    def test_notifications_handler_dismiss(self):
        state = CourseRerunUIStateManager.State.FAILED
        should_display = True
        rerun_course_key = CourseLocator(org='testx',
                                         course='test_course',
                                         run='test_run')

        # add an instructor to this course
        user2 = UserFactory()
        add_instructor(rerun_course_key, self.user, user2)

        # create a test notification
        rerun_state = CourseRerunState.objects.update_state(
            course_key=rerun_course_key, new_state=state, allow_not_found=True)
        CourseRerunState.objects.update_should_display(
            entry_id=rerun_state.id, user=user2, should_display=should_display)

        # try to get information on this notification
        notification_dismiss_url = reverse_course_url(
            'course_notifications_handler',
            self.course.id,
            kwargs={
                'action_state_id': rerun_state.id,
            })
        resp = self.client.delete(notification_dismiss_url)
        self.assertEqual(resp.status_code, 200)

        with self.assertRaises(CourseRerunState.DoesNotExist):
            # delete nofications that are dismissed
            CourseRerunState.objects.get(id=rerun_state.id)

        self.assertFalse(has_course_author_access(user2, rerun_course_key))
 def setUp(self):
     """
     Setup test course, user, and url.
     """
     super().setUp()
     self.course_module = modulestore().get_course(self.course.id)
     self.test_url = reverse_course_url('export_git', self.course.id)
Exemple #12
0
    def test_certificate_activation_success(self, signatory_path):
        """
        Activate and Deactivate the course certificate
        """
        test_url = reverse_course_url('certificate_activation_handler',
                                      self.course.id)
        self._add_course_certificates(count=1,
                                      signatory_count=2,
                                      asset_path_format=signatory_path)

        is_active = True
        for i in range(2):
            if i == 1:
                is_active = not is_active
            response = self.client.post(test_url,
                                        data=json.dumps(
                                            {"is_active": is_active}),
                                        content_type="application/json",
                                        HTTP_ACCEPT="application/json",
                                        HTTP_X_REQUESTED_WITH="XMLHttpRequest")
            self.assertEqual(response.status_code, 200)
            course = self.store.get_course(self.course.id)
            certificates = course.certificates['certificates']
            self.assertEqual(certificates[0].get('is_active'), is_active)
            cert_event_type = 'activated' if is_active else 'deactivated'
            self.assert_event_emitted(
                '.'.join(['edx.certificate.configuration', cert_event_type]),
                course_id=str(self.course.id),
            )
 def test_output_non_course_author(self):
     """
     Verify that users who aren't authors of the course are unable to see the output of export tasks
     """
     client, _ = self.create_non_staff_authed_user_client()
     resp = client.get(reverse_course_url('export_output_handler', self.course.id))
     self.assertEqual(resp.status_code, 403)
Exemple #14
0
    def test_manage_library_users(self):
        """
        Simple test that the Library "User Access" view works.
        Also tests that we can use the REST API to assign a user to a library.
        """
        library = LibraryFactory.create()
        extra_user, _ = self.create_non_staff_user()
        manage_users_url = reverse_library_url(
            'manage_library_users', str(library.location.library_key))

        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        # extra_user has not been assigned to the library so should not show up in the list:
        self.assertNotContains(response, extra_user.username)

        # Now add extra_user to the library:
        user_details_url = reverse_course_url(
            'course_team_handler',
            library.location.library_key,
            kwargs={'email': extra_user.email})
        edit_response = self.client.ajax_post(user_details_url,
                                              {"role": LibraryUserRole.ROLE})
        self.assertIn(edit_response.status_code, (200, 204))

        # Now extra_user should apear in the list:
        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, extra_user.username)
Exemple #15
0
 def setUp(self):
     """
     Setup test course, user, and url.
     """
     super(TestExportGit, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments
     self.course_module = modulestore().get_course(self.course.id)
     self.test_url = reverse_course_url('export_git', self.course.id)
    def setUp(self):
        super(ImportEntranceExamTestCase, self).setUp()
        self.url = reverse_course_url('import_handler', self.course.id)
        self.content_dir = path(tempfile.mkdtemp())
        self.addCleanup(shutil.rmtree, self.content_dir)

        # Create tar test file -----------------------------------------------
        # OK course with entrance exam section:
        entrance_exam_dir = tempfile.mkdtemp(dir=self.content_dir)
        # test course being deeper down than top of tar file
        embedded_exam_dir = os.path.join(entrance_exam_dir, "grandparent", "parent")
        os.makedirs(os.path.join(embedded_exam_dir, "course"))
        os.makedirs(os.path.join(embedded_exam_dir, "chapter"))
        with open(os.path.join(embedded_exam_dir, "course.xml"), "w+") as f:
            f.write('<course url_name="2013_Spring" org="EDx" course="0.00x"/>')

        with open(os.path.join(embedded_exam_dir, "course", "2013_Spring.xml"), "w+") as f:
            f.write(
                '<course '
                'entrance_exam_enabled="true" entrance_exam_id="xyz" entrance_exam_minimum_score_pct="0.7">'
                '<chapter url_name="2015_chapter_entrance_exam"/></course>'
            )

        with open(os.path.join(embedded_exam_dir, "chapter", "2015_chapter_entrance_exam.xml"), "w+") as f:
            f.write('<chapter display_name="Entrance Exam" in_entrance_exam="true" is_entrance_exam="true"></chapter>')

        self.entrance_exam_tar = os.path.join(self.content_dir, "entrance_exam.tar.gz")
        with tarfile.open(self.entrance_exam_tar, "w:gz") as gtar:
            gtar.add(entrance_exam_dir)
    def setUp(self):
        super(ImportTestCase, self).setUp()
        self.url = reverse_course_url('import_handler', self.course.id)
        self.content_dir = path(tempfile.mkdtemp())
        self.addCleanup(shutil.rmtree, self.content_dir)

        def touch(name):
            """ Equivalent to shell's 'touch'"""
            with open(name, 'a'):  # pylint: disable=W6005
                os.utime(name, None)

        # Create tar test files -----------------------------------------------
        # OK course:
        good_dir = tempfile.mkdtemp(dir=self.content_dir)
        # test course being deeper down than top of tar file
        embedded_dir = os.path.join(good_dir, "grandparent", "parent")
        os.makedirs(os.path.join(embedded_dir, "course"))
        with open(os.path.join(embedded_dir, "course.xml"), "w+") as f:
            f.write('<course url_name="2013_Spring" org="EDx" course="0.00x"/>')

        with open(os.path.join(embedded_dir, "course", "2013_Spring.xml"), "w+") as f:
            f.write('<course></course>')

        self.good_tar = os.path.join(self.content_dir, "good.tar.gz")
        with tarfile.open(self.good_tar, "w:gz") as gtar:
            gtar.add(good_dir)

        # Bad course (no 'course.xml' file):
        bad_dir = tempfile.mkdtemp(dir=self.content_dir)
        touch(os.path.join(bad_dir, "bad.xml"))
        self.bad_tar = os.path.join(self.content_dir, "bad.tar.gz")
        with tarfile.open(self.bad_tar, "w:gz") as btar:
            btar.add(bad_dir)

        self.unsafe_common_dir = path(tempfile.mkdtemp(dir=self.content_dir))
 def get_details_url(self, textbook_id):
     """
     Returns the URL for textbook detail handler.
     """
     return reverse_course_url('textbooks_detail_handler',
                               self.course.id,
                               kwargs={'textbook_id': textbook_id})
Exemple #19
0
 def test_delete_asset(self):
     """ Tests the happy path :) """
     test_url = reverse_course_url(
         'assets_handler',
         self.course.id,
         kwargs={'asset_key_string': six.text_type(self.uploaded_url)})
     resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
     self.assertEqual(resp.status_code, 204)
 def test_delete_asset_with_invalid_thumbnail(self):
     """ Tests the sad path :( """
     test_url = reverse_course_url(
         'assets_handler', self.course.id, kwargs={'asset_key_string': str(self.uploaded_url)})
     self.content.thumbnail_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/invalid')
     contentstore().save(self.content)
     resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
     self.assertEqual(resp.status_code, 204)
 def setUp(self):
     super().setUp()
     self.url = reverse_course_url('assets_handler', self.course.id)
     # First, upload something.
     self.asset_name = 'download_test'
     resp = self.upload_asset(self.asset_name)
     self.assertEqual(resp.status_code, 200)
     self.uploaded_url = json.loads(resp.content.decode('utf-8'))['asset']['url']
Exemple #22
0
    def test_course_index_invalid_url(self):
        """
        Tests the error conditions for the invalid course index URL.
        """
        # Testing the response code by passing slash separated course key, no course
        # having this key exists.
        invalid_course_key = '{}_some_invalid_run'.format(self.course.id)
        course_outline_url = reverse_course_url('course_handler', invalid_course_key)
        response = self.client.get_html(course_outline_url)
        self.assertEqual(response.status_code, 404)

        # Testing the response code by passing split course key, no course
        # having this key exists.
        split_course_key = CourseLocator(org='invalid_org', course='course_01111', run='Run_0_invalid')
        course_outline_url_split = reverse_course_url('course_handler', split_course_key)
        response = self.client.get_html(course_outline_url_split)
        self.assertEqual(response.status_code, 404)
 def test_delete_asset_with_invalid_asset(self):
     """ Tests the sad path :( """
     test_url = reverse_course_url(
         'assets_handler',
         self.course.id, kwargs={'asset_key_string': "/c4x/edX/toy/asset/invalid.pdf"}
     )
     resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
     self.assertEqual(resp.status_code, 404)
Exemple #24
0
 def setUp(self):
     super(DownloadTestCase, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments
     self.url = reverse_course_url('assets_handler', self.course.id)
     # First, upload something.
     self.asset_name = 'download_test'
     resp = self.upload_asset(self.asset_name)
     self.assertEqual(resp.status_code, 200)
     self.uploaded_url = json.loads(
         resp.content.decode('utf-8'))['asset']['url']
Exemple #25
0
 def test_negative_conditions(self):
     """
     Test the error conditions for the access
     """
     outline_url = reverse_course_url('course_handler', self.course.id)
     # register a non-staff member and try to delete the course branch
     non_staff_client, _ = self.create_non_staff_authed_user_client()
     response = non_staff_client.delete(outline_url, {}, HTTP_ACCEPT='application/json')
     self.assertEqual(response.status_code, 403)
 def test_view_with_exam_settings_enabled(self, handler):
     """
     Tests pages should have `Exam Settings` item
     if course does have Exam Settings view enabled.
     """
     outline_url = reverse_course_url(handler, self.course.id)
     resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
     self.assertEqual(resp.status_code, 200)
     self.assertContains(resp, 'Proctored Exam Settings')
 def test_exam_settings_alert_not_shown(self, page_handler):
     """
     Alert should not be visible if no proctored exam setting error exists
     """
     url = reverse_course_url(page_handler, self.course.id)
     resp = self.client.get(url, HTTP_ACCEPT='text/html')
     parsed_html = lxml.html.fromstring(resp.content)
     alert_nodes = parsed_html.find_class('exam-settings-alert')
     assert len(alert_nodes) == 0
 def test_header_menu_with_exam_settings_enabled(self):
     """
     Tests course header menu should have `Exam Settings` menu item
     if course does have Exam Settings view enabled.
     """
     outline_url = reverse_course_url('course_handler', self.course.id)
     resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
     self.assertEqual(resp.status_code, 200)
     self.assertContains(resp,
                         '<li class="nav-item nav-course-settings-exams">')
Exemple #29
0
 def _url(self, cid=-1):
     """
     Return url for the handler.
     """
     cid = cid if cid > 0 else self._id
     return reverse_course_url(
         'certificates_detail_handler',
         self.course.id,
         kwargs={'certificate_id': cid},
     )
Exemple #30
0
 def _url(self, cid=-1):
     """
     Return url for the handler.
     """
     cid = cid if cid > 0 else self.ID
     return reverse_course_url(
         'group_configurations_detail_handler',
         self.course.id,
         kwargs={'group_configuration_id': cid},
     )