<commit_before>"""
This test file will run through some LMS test scenarios regarding access and navigation of the LMS
"""
from __future__ import absolute_import

import time

from django.conf import settings
from django.test.utils import override_settings
from django.urls import reverse
from mock import patch
from six import text_type
from six.moves import range

from courseware.tests.factories import GlobalStaffFactory
from courseware.tests.helpers import LoginEnrollmentTestCase
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.features.course_experience import COURSE_OUTLINE_PAGE_FLAG
from student.tests.factories import UserFactory
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory


class TestNavigation(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
    """
    Check that navigation state is saved properly.
    """
    STUDENT_INFO = [('<EMAIL>', 'foo'), ('<EMAIL>', 'foo')]

    @classmethod
    def setUpClass(cls):
        # pylint: disable=super-method-not-called
        with super(TestNavigation, cls).setUpClassAndTestData():
            cls.test_course = CourseFactory.create()
            cls.test_course_proctored = CourseFactory.create()
            cls.course = CourseFactory.create()

    @classmethod
    def setUpTestData(cls):
        cls.chapter0 = ItemFactory.create(parent=cls.course,
                                          display_name='Overview')
        cls.chapter9 = ItemFactory.create(parent=cls.course,
                                          display_name='factory_chapter')
        cls.section0 = ItemFactory.create(parent=cls.chapter0,
                                          display_name='Welcome')
        cls.section9 = ItemFactory.create(parent=cls.chapter9,
                                          display_name='factory_section')
        cls.unit0 = ItemFactory.create(parent=cls.section0,
                                       display_name='New Unit 0')

        cls.chapterchrome = ItemFactory.create(parent=cls.course,
                                               display_name='Chrome')
        cls.chromelesssection = ItemFactory.create(parent=cls.chapterchrome,
                                                   display_name='chromeless',
                                                   chrome='none')
        cls.accordionsection = ItemFactory.create(parent=cls.chapterchrome,
                                                  display_name='accordion',
                                                  chrome='accordion')
        cls.tabssection = ItemFactory.create(parent=cls.chapterchrome,
                                             display_name='tabs',
                                             chrome='tabs')
        cls.defaultchromesection = ItemFactory.create(
            parent=cls.chapterchrome,
            display_name='defaultchrome',
        )
        cls.fullchromesection = ItemFactory.create(parent=cls.chapterchrome,
                                                   display_name='fullchrome',
                                                   chrome='accordion,tabs')
        cls.tabtest = ItemFactory.create(parent=cls.chapterchrome,
                                         display_name='pdf_textbooks_tab',
                                         default_tab='progress')

        cls.staff_user = GlobalStaffFactory()
        cls.user = UserFactory()

    def setUp(self):
        super(TestNavigation, self).setUp()

        # Create student accounts and activate them.
        for i in range(len(self.STUDENT_INFO)):
            email, password = self.STUDENT_INFO[i]
            username = 'u{0}'.format(i)
            self.create_account(username, email, password)
            self.activate_user(email)

    def assertTabActive(self, tabname, response):
        ''' Check if the progress tab is active in the tab set '''
        for line in response.content.decode('utf-8').split('\n'):
            if tabname in line and 'active' in line:
                return
        raise AssertionError(u"assertTabActive failed: {} not active".format(tabname))

    def assertTabInactive(self, tabname, response):
        ''' Check if the progress tab is active in the tab set '''
        for line in response.content.decode('utf-8').split('\n'):
            if tabname in line and 'active' in line:
                raise AssertionError("assertTabInactive failed: " + tabname + " active")
        return

    # TODO: LEARNER-71: Do we need to adjust or remove this test?
    @override_waffle_flag(COURSE_OUTLINE_PAGE_FLAG, active=False)
    def test_chrome_settings(self):
        '''
        Test settings for disabling and modifying navigation chrome in the courseware:
        - Accordion enabled, or disabled
        - Navigation tabs enabled, disabled, or redirected
        '''
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)

        test_data = (
            ('tabs', False, True),
            ('none', False, False),
            ('fullchrome', True, True),
            ('accordion', True, False),
            ('fullchrome', True, True)
        )
        for (displayname, accordion, tabs) in test_data:
            response = self.client.get(reverse('courseware_section', kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'Chrome',
                'section': displayname,
            }))
            self.assertEqual('course-tabs' in response.content.decode('utf-8'), tabs)
            self.assertEqual('course-navigation' in response.content.decode('utf-8'), accordion)

        self.assertTabInactive('progress', response)
        self.assertTabActive('courseware', response)

        response = self.client.get(reverse('courseware_section', kwargs={
            'course_id': text_type(self.course.id),
            'chapter': 'Chrome',
            'section': 'pdf_textbooks_tab',
        }))

        self.assertTabActive('progress', response)
        self.assertTabInactive('courseware', response)

    @override_settings(SESSION_INACTIVITY_TIMEOUT_IN_SECONDS=1)
    def test_inactive_session_timeout(self):
        """
        Verify that an inactive session times out and redirects to the
        login page
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)

        # make sure we can access courseware immediately
        resp = self.client.get(reverse('dashboard'))
        self.assertEqual(resp.status_code, 200)

        # then wait a bit and see if we get timed out
        time.sleep(2)

        resp = self.client.get(reverse('dashboard'))

        # re-request, and we should get a redirect to login page
        self.assertRedirects(resp, settings.LOGIN_REDIRECT_URL + '?next=' + reverse('dashboard'))

    def test_redirects_first_time(self):
        """
        Verify that the first time we click on the courseware tab we are
        redirected to the 'Welcome' section.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        resp = self.client.get(reverse('courseware',
                               kwargs={'course_id': text_type(self.course.id)}))
        self.assertRedirects(resp, reverse(
            'courseware_section', kwargs={'course_id': text_type(self.course.id),
                                          'chapter': 'Overview',
                                          'section': 'Welcome'}))

    def test_redirects_second_time(self):
        """
        Verify the accordion remembers we've already visited the Welcome section
        and redirects correspondingly.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        section_url = reverse(
            'courseware_section',
            kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'Overview',
                'section': 'Welcome',
            },
        )
        self.client.get(section_url)
        resp = self.client.get(
            reverse('courseware', kwargs={'course_id': text_type(self.course.id)}),
        )
        self.assertRedirects(resp, section_url)

    def test_accordion_state(self):
        """
        Verify the accordion remembers which chapter you were last viewing.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        # Now we directly navigate to a section in a chapter other than 'Overview'.
        section_url = reverse(
            'courseware_section',
            kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'factory_chapter',
                'section': 'factory_section',
            }
        )
        self.assert_request_status_code(200, section_url)

        # And now hitting the courseware tab should redirect to 'factory_chapter'
        url = reverse(
            'courseware',
            kwargs={'course_id': text_type(self.course.id)}
        )
        resp = self.client.get(url)
        self.assertRedirects(resp, section_url)

    # TODO: LEARNER-71: Do we need to adjust or remove this test?
    @override_waffle_flag(COURSE_OUTLINE_PAGE_FLAG, active=False)
    def test_incomplete_course(self):
        email = self.staff_user.email
        password = "<PASSWORD>"
        self.login(email, password)
        self.enroll(self.test_course, True)

        test_course_id = text_type(self.test_course.id)

        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertIn("No content has been added to this course", response.content.decode('utf-8'))

        section = ItemFactory.create(
            parent_location=self.test_course.location,
            display_name='New Section'
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertNotIn("No content has been added to this course", response.content.decode('utf-8'))
        self.assertIn("New Section", response.content.decode('utf-8'))

        subsection = ItemFactory.create(
            parent_location=section.location,
            display_name='New Subsection',
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertIn("New Subsection", response.content.decode('utf-8'))
        self.assertNotIn("sequence-nav", response.content.decode('utf-8'))

        ItemFactory.create(
            parent_location=subsection.location,
            display_name='New Unit',
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        self.assert_request_status_code(302, url)

    def test_proctoring_js_includes(self):
        """
        Make sure that proctoring JS does not get included on
        courseware pages if either the FEATURE flag is turned off
        or the course is not proctored enabled
        """

        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.test_course_proctored, True)

        test_course_id = text_type(self.test_course_proctored.id)

        with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': False}):
            url = reverse(
                'courseware',
                kwargs={'course_id': test_course_id}
            )
            resp = self.client.get(url)

            self.assertNotContains(resp, '/static/js/lms-proctoring.js')

        with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': True}):
            url = reverse(
                'courseware',
                kwargs={'course_id': test_course_id}
            )
            resp = self.client.get(url)

            self.assertNotContains(resp, '/static/js/lms-proctoring.js')

            # now set up a course which is proctored enabled

            self.test_course_proctored.enable_proctored_exams = True
            self.test_course_proctored.save()

            modulestore().update_item(self.test_course_proctored, self.user.id)

            resp = self.client.get(url)

            self.assertContains(resp, '/static/js/lms-proctoring.js')
<commit_msg>BOM-104 Fixed failing unittest<commit_after>"""
This test file will run through some LMS test scenarios regarding access and navigation of the LMS
"""
from __future__ import absolute_import

import time

from django.conf import settings
from django.test.utils import override_settings
from django.urls import reverse
from mock import patch
from six import text_type
from six.moves import range

from courseware.tests.factories import GlobalStaffFactory
from courseware.tests.helpers import LoginEnrollmentTestCase
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.features.course_experience import COURSE_OUTLINE_PAGE_FLAG
from student.tests.factories import UserFactory
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory


class TestNavigation(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
    """
    Check that navigation state is saved properly.
    """
    STUDENT_INFO = [('<EMAIL>', 'foo'), ('<EMAIL>', 'foo')]

    @classmethod
    def setUpClass(cls):
        # pylint: disable=super-method-not-called
        with super(TestNavigation, cls).setUpClassAndTestData():
            cls.test_course = CourseFactory.create()
            cls.test_course_proctored = CourseFactory.create()
            cls.course = CourseFactory.create()

    @classmethod
    def setUpTestData(cls):
        cls.chapter0 = ItemFactory.create(parent=cls.course,
                                          display_name='Overview')
        cls.chapter9 = ItemFactory.create(parent=cls.course,
                                          display_name='factory_chapter')
        cls.section0 = ItemFactory.create(parent=cls.chapter0,
                                          display_name='Welcome')
        cls.section9 = ItemFactory.create(parent=cls.chapter9,
                                          display_name='factory_section')
        cls.unit0 = ItemFactory.create(parent=cls.section0,
                                       display_name='New Unit 0')

        cls.chapterchrome = ItemFactory.create(parent=cls.course,
                                               display_name='Chrome')
        cls.chromelesssection = ItemFactory.create(parent=cls.chapterchrome,
                                                   display_name='chromeless',
                                                   chrome='none')
        cls.accordionsection = ItemFactory.create(parent=cls.chapterchrome,
                                                  display_name='accordion',
                                                  chrome='accordion')
        cls.tabssection = ItemFactory.create(parent=cls.chapterchrome,
                                             display_name='tabs',
                                             chrome='tabs')
        cls.defaultchromesection = ItemFactory.create(
            parent=cls.chapterchrome,
            display_name='defaultchrome',
        )
        cls.fullchromesection = ItemFactory.create(parent=cls.chapterchrome,
                                                   display_name='fullchrome',
                                                   chrome='accordion,tabs')
        cls.tabtest = ItemFactory.create(parent=cls.chapterchrome,
                                         display_name='pdf_textbooks_tab',
                                         default_tab='progress')

        cls.staff_user = GlobalStaffFactory()
        cls.user = UserFactory()

    def setUp(self):
        super(TestNavigation, self).setUp()

        # Create student accounts and activate them.
        for i in range(len(self.STUDENT_INFO)):
            email, password = self.STUDENT_INFO[i]
            username = 'u{0}'.format(i)
            self.create_account(username, email, password)
            self.activate_user(email)

    def assertTabActive(self, tabname, response):
        ''' Check if the progress tab is active in the tab set '''
        for line in response.content.decode('utf-8').split('\n'):
            if tabname in line and 'active' in line:
                return
        raise AssertionError(u"assertTabActive failed: {} not active".format(tabname))

    def assertTabInactive(self, tabname, response):
        ''' Check if the progress tab is active in the tab set '''
        for line in response.content.decode('utf-8').split('\n'):
            if tabname in line and 'active' in line:
                raise AssertionError("assertTabInactive failed: " + tabname + " active")
        return

    # TODO: LEARNER-71: Do we need to adjust or remove this test?
    @override_waffle_flag(COURSE_OUTLINE_PAGE_FLAG, active=False)
    def test_chrome_settings(self):
        '''
        Test settings for disabling and modifying navigation chrome in the courseware:
        - Accordion enabled, or disabled
        - Navigation tabs enabled, disabled, or redirected
        '''
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)

        test_data = (
            ('tabs', False, True),
            ('none', False, False),
            ('accordion', True, False),
            ('fullchrome', True, True),
        )
        for (displayname, accordion, tabs) in test_data:
            response = self.client.get(reverse('courseware_section', kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'Chrome',
                'section': displayname,
            }))
            self.assertEqual('course-tabs' in response.content.decode('utf-8'), tabs)
            self.assertEqual('course-navigation' in response.content.decode('utf-8'), accordion)

        self.assertTabInactive('progress', response)
        self.assertTabActive('courseware', response)

        response = self.client.get(reverse('courseware_section', kwargs={
            'course_id': text_type(self.course.id),
            'chapter': 'Chrome',
            'section': 'pdf_textbooks_tab',
        }))

        self.assertTabActive('progress', response)
        self.assertTabInactive('courseware', response)

    @override_settings(SESSION_INACTIVITY_TIMEOUT_IN_SECONDS=1)
    def test_inactive_session_timeout(self):
        """
        Verify that an inactive session times out and redirects to the
        login page
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)

        # make sure we can access courseware immediately
        resp = self.client.get(reverse('dashboard'))
        self.assertEqual(resp.status_code, 200)

        # then wait a bit and see if we get timed out
        time.sleep(2)

        resp = self.client.get(reverse('dashboard'))

        # re-request, and we should get a redirect to login page
        self.assertRedirects(resp, settings.LOGIN_REDIRECT_URL + '?next=' + reverse('dashboard'))

    def test_redirects_first_time(self):
        """
        Verify that the first time we click on the courseware tab we are
        redirected to the 'Welcome' section.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        resp = self.client.get(reverse('courseware',
                               kwargs={'course_id': text_type(self.course.id)}))
        self.assertRedirects(resp, reverse(
            'courseware_section', kwargs={'course_id': text_type(self.course.id),
                                          'chapter': 'Overview',
                                          'section': 'Welcome'}))

    def test_redirects_second_time(self):
        """
        Verify the accordion remembers we've already visited the Welcome section
        and redirects correspondingly.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        section_url = reverse(
            'courseware_section',
            kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'Overview',
                'section': 'Welcome',
            },
        )
        self.client.get(section_url)
        resp = self.client.get(
            reverse('courseware', kwargs={'course_id': text_type(self.course.id)}),
        )
        self.assertRedirects(resp, section_url)

    def test_accordion_state(self):
        """
        Verify the accordion remembers which chapter you were last viewing.
        """
        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.course, True)
        self.enroll(self.test_course, True)

        # Now we directly navigate to a section in a chapter other than 'Overview'.
        section_url = reverse(
            'courseware_section',
            kwargs={
                'course_id': text_type(self.course.id),
                'chapter': 'factory_chapter',
                'section': 'factory_section',
            }
        )
        self.assert_request_status_code(200, section_url)

        # And now hitting the courseware tab should redirect to 'factory_chapter'
        url = reverse(
            'courseware',
            kwargs={'course_id': text_type(self.course.id)}
        )
        resp = self.client.get(url)
        self.assertRedirects(resp, section_url)

    # TODO: LEARNER-71: Do we need to adjust or remove this test?
    @override_waffle_flag(COURSE_OUTLINE_PAGE_FLAG, active=False)
    def test_incomplete_course(self):
        email = self.staff_user.email
        password = "<PASSWORD>"
        self.login(email, password)
        self.enroll(self.test_course, True)

        test_course_id = text_type(self.test_course.id)

        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertIn("No content has been added to this course", response.content.decode('utf-8'))

        section = ItemFactory.create(
            parent_location=self.test_course.location,
            display_name='New Section'
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertNotIn("No content has been added to this course", response.content.decode('utf-8'))
        self.assertIn("New Section", response.content.decode('utf-8'))

        subsection = ItemFactory.create(
            parent_location=section.location,
            display_name='New Subsection',
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        response = self.assert_request_status_code(200, url)
        self.assertIn("New Subsection", response.content.decode('utf-8'))
        self.assertNotIn("sequence-nav", response.content.decode('utf-8'))

        ItemFactory.create(
            parent_location=subsection.location,
            display_name='New Unit',
        )
        url = reverse(
            'courseware',
            kwargs={'course_id': test_course_id}
        )
        self.assert_request_status_code(302, url)

    def test_proctoring_js_includes(self):
        """
        Make sure that proctoring JS does not get included on
        courseware pages if either the FEATURE flag is turned off
        or the course is not proctored enabled
        """

        email, password = self.STUDENT_INFO[0]
        self.login(email, password)
        self.enroll(self.test_course_proctored, True)

        test_course_id = text_type(self.test_course_proctored.id)

        with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': False}):
            url = reverse(
                'courseware',
                kwargs={'course_id': test_course_id}
            )
            resp = self.client.get(url)

            self.assertNotContains(resp, '/static/js/lms-proctoring.js')

        with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': True}):
            url = reverse(
                'courseware',
                kwargs={'course_id': test_course_id}
            )
            resp = self.client.get(url)

            self.assertNotContains(resp, '/static/js/lms-proctoring.js')

            # now set up a course which is proctored enabled

            self.test_course_proctored.enable_proctored_exams = True
            self.test_course_proctored.save()

            modulestore().update_item(self.test_course_proctored, self.user.id)

            resp = self.client.get(url)

            self.assertContains(resp, '/static/js/lms-proctoring.js')

{'fraction_non_alphanumeric': 0.09691852774103182, 'fraction_numerical': 0.003929655279744767, 'mean_word_length': 2.0960009636232235, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 70, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '929204', 'n_tokens_mistral': 6887, 'n_tokens_neox': 6673, 'n_words': 1472}