def instrument_course_progress_render(
            self, course_width, enable_ccx, view_as_ccx,
            sql_queries, mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_all_namespaces()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(sql_queries, using='default', table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
Exemple #2
0
    def test_request_context_caching(self):
        """
        Test that the RequestContext is cached in the RequestCache.
        """
        with patch(
                'common.djangoapps.edxmako.request_context.get_current_request',
                return_value=None):
            # requestcontext should be None, because the cache isn't filled
            assert get_template_request_context() is None

        with patch(
                'common.djangoapps.edxmako.request_context.get_current_request',
                return_value=self.request):
            # requestcontext should not be None, and should fill the cache
            assert get_template_request_context() is not None

        mock_get_current_request = Mock()
        with patch(
                'common.djangoapps.edxmako.request_context.get_current_request'
        ):
            with patch(
                    'common.djangoapps.edxmako.request_context.RequestContext.__init__'
            ) as mock_context_init:
                # requestcontext should not be None, because the cache is filled
                assert get_template_request_context() is not None
                mock_context_init.assert_not_called()
        mock_get_current_request.assert_not_called()

        RequestCache.clear_all_namespaces()

        with patch(
                'common.djangoapps.edxmako.request_context.get_current_request',
                return_value=None):
            # requestcontext should be None, because the cache isn't filled
            assert get_template_request_context() is None
Exemple #3
0
 def test_setting_override(self, is_enabled, override_choice, expected_result):
     RequestCache.clear_all_namespaces()
     self.set_waffle_course_override(override_choice, is_enabled)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY
     )
     self.assertEqual(override_value, expected_result)
    def test_request_context_caching(self):
        """
        Test that the RequestContext is cached in the RequestCache.
        """
        with patch('edxmako.request_context.get_current_request',
                   return_value=None):
            # requestcontext should be None, because the cache isn't filled
            self.assertIsNone(get_template_request_context())

        with patch('edxmako.request_context.get_current_request',
                   return_value=self.request):
            # requestcontext should not be None, and should fill the cache
            self.assertIsNotNone(get_template_request_context())

        mock_get_current_request = Mock()
        with patch('edxmako.request_context.get_current_request',
                   mock_get_current_request):
            # requestcontext should not be None, because the cache is filled
            self.assertIsNotNone(get_template_request_context())
        mock_get_current_request.assert_not_called()

        RequestCache.clear_all_namespaces()

        with patch('edxmako.request_context.get_current_request',
                   return_value=None):
            # requestcontext should be None, because the cache isn't filled
            self.assertIsNone(get_template_request_context())
Exemple #5
0
    def instrument_course_progress_render(
            self, course_width, enable_ccx, view_as_ccx,
            sql_queries, mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_all_namespaces()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(sql_queries, using='default', table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
Exemple #6
0
 def test_setting_override_multiple_times(self):
     RequestCache.clear_all_namespaces()
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.on)
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.off)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY)
     self.assertEqual(override_value, self.OVERRIDE_CHOICES.off)
Exemple #7
0
    def test_get_template_path(self):
        """
        Tests to make sure the get_template_path function works as expected.
        """
        # if the current site has associated SiteTheme then get_template_path should return the argument as is.
        with patch(
            "openedx.core.djangoapps.theming.helpers.current_request_has_associated_site_theme",
            Mock(return_value=True),
        ):
            with patch(
                "openedx.core.djangoapps.theming.helpers.microsite.is_request_in_microsite",
                Mock(return_value=True),
            ):
                with patch("microsite_configuration.microsite.TEMPLATES_BACKEND") as mock_microsite_backend:
                    mock_microsite_backend.get_template = Mock(return_value="/microsite/about.html")
                    self.assertEqual(theming_helpers.get_template_path("about.html"), "about.html")

        RequestCache.clear_all_namespaces()

        # if the current site does not have associated SiteTheme then get_template_path should return microsite override
        with patch(
            "openedx.core.djangoapps.theming.helpers.current_request_has_associated_site_theme",
            Mock(return_value=False),
        ):
            with patch(
                "openedx.core.djangoapps.theming.helpers.microsite.is_request_in_microsite",
                Mock(return_value=True),
            ):
                with patch("microsite_configuration.microsite.TEMPLATES_BACKEND") as mock_microsite_backend:
                    mock_microsite_backend.get_template_path = Mock(return_value="/microsite/about.html")
                    self.assertEqual(theming_helpers.get_template_path("about.html"), "/microsite/about.html")
Exemple #8
0
 def test_setting_override(self, is_enabled, override_choice,
                           expected_result):
     RequestCache.clear_all_namespaces()
     self.set_waffle_course_override(override_choice, is_enabled)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY)
     self.assertEqual(override_value, expected_result)
    def test_request_cached_with_caches_despite_changing_wrapped_result(self):
        """
        Ensure that after caching a result, we always send it back, even if the underlying result changes.
        """
        RequestCache.clear_all_namespaces()

        to_be_wrapped = Mock()
        to_be_wrapped.side_effect = [1, 2, 3]
        self.assertEqual(to_be_wrapped.call_count, 0)

        def mock_wrapper(*args, **kwargs):
            """Simple wrapper to let us decorate our mock."""
            return to_be_wrapped(*args, **kwargs)

        wrapped = request_cached(mock_wrapper)
        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        direct_result = mock_wrapper()
        self.assertEqual(direct_result, 2)
        self.assertEqual(to_be_wrapped.call_count, 2)

        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 2)

        direct_result = mock_wrapper()
        self.assertEqual(direct_result, 3)
        self.assertEqual(to_be_wrapped.call_count, 3)
Exemple #10
0
def _clear_request_cache(**kwargs):
    """
    Once a celery task completes, clear the request cache to
    prevent memory leaks.
    """
    if getattr(settings, 'CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION', True):
        RequestCache.clear_all_namespaces()
    def test_caching_org(self):
        course = CourseOverviewFactory.create(org='test-org')
        site_cfg = SiteConfigurationFactory.create(
            site_values={'course_org_filter': course.org},
            values={'course_org_filter': course.org})
        org_config = CourseDurationLimitConfig(org=course.org,
                                               enabled=True,
                                               enabled_as_of=datetime(
                                                   2018, 1, 1))
        org_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not retrieved from cache after save
        with self.assertNumQueries(2):
            self.assertTrue(
                CourseDurationLimitConfig.current(org=course.org).enabled)

        RequestCache.clear_all_namespaces()

        # Check that the org value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(
                CourseDurationLimitConfig.current(org=course.org).enabled)

        org_config.enabled = False
        org_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value in cache was deleted on save
        with self.assertNumQueries(2):
            self.assertFalse(
                CourseDurationLimitConfig.current(org=course.org).enabled)

        global_config = CourseDurationLimitConfig(enabled=True,
                                                  enabled_as_of=datetime(
                                                      2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not updated in cache by changing the global value
        with self.assertNumQueries(0):
            self.assertFalse(
                CourseDurationLimitConfig.current(org=course.org).enabled)

        site_config = CourseDurationLimitConfig(site=site_cfg.site,
                                                enabled=True,
                                                enabled_as_of=datetime(
                                                    2018, 1, 1))
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not updated in cache by changing the site value
        with self.assertNumQueries(0):
            self.assertFalse(
                CourseDurationLimitConfig.current(org=course.org).enabled)
Exemple #12
0
 def test_setting_override_multiple_times(self):
     RequestCache.clear_all_namespaces()
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.on)
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.off)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY
     )
     self.assertEqual(override_value, self.OVERRIDE_CHOICES.off)
Exemple #13
0
    def test_too_many_courses(self):
        """
        Test that search results are limited to 100 courses, and that they don't
        blow up the database.
        """

        ContentTypeGatingConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        CourseDurationLimitConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        course_ids = []

        # Create 300 courses across 30 organizations
        for org_num in range(10):
            org_id = f'org{org_num}'
            for course_num in range(30):
                course_name = f'course{org_num}.{course_num}'
                course_run_name = f'run{org_num}.{course_num}'
                course = CourseFactory.create(org=org_id,
                                              number=course_name,
                                              run=course_run_name,
                                              emit_signals=True)
                CourseModeFactory.create(course_id=course.id,
                                         mode_slug=CourseMode.AUDIT)
                CourseModeFactory.create(course_id=course.id,
                                         mode_slug=CourseMode.VERIFIED)
                course_ids.append(course.id)

        self.setup_user(self.audit_user)

        # These query counts were found empirically
        query_counts = [50, 46, 46, 46, 46, 46, 46, 46, 46, 46, 16]
        ordered_course_ids = sorted(
            [str(cid) for cid in (course_ids + [c.id for c in self.courses])])

        self.clear_caches()

        for page in range(1, 12):
            RequestCache.clear_all_namespaces()
            with self.assertNumQueries(query_counts[page - 1],
                                       table_ignorelist=WAFFLE_TABLES):
                response = self.verify_response(params={
                    'page': page,
                    'page_size': 30
                })

                assert 'results' in response.data
                assert response.data['pagination']['count'] == 303
                assert len(response.data['results']) == (30 if
                                                         (page < 11) else 3)
                assert [c['id'] for c in response.data['results']
                        ] == ordered_course_ids[((page - 1) * 30):(page * 30)]
Exemple #14
0
    def test_too_many_courses(self):
        """
        Test that search results are limited to 100 courses, and that they don't
        blow up the database.
        """

        ContentTypeGatingConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        CourseDurationLimitConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        course_ids = []

        # Create 300 courses across 30 organizations
        for org_num in range(10):
            org_id = 'org{}'.format(org_num)
            for course_num in range(30):
                course_name = 'course{}.{}'.format(org_num, course_num)
                course_run_name = 'run{}.{}'.format(org_num, course_num)
                course = CourseFactory.create(org=org_id,
                                              number=course_name,
                                              run=course_run_name,
                                              emit_signals=True)
                CourseModeFactory.create(course_id=course.id,
                                         mode_slug=CourseMode.AUDIT)
                CourseModeFactory.create(course_id=course.id,
                                         mode_slug=CourseMode.VERIFIED)
                course_ids.append(course.id)

        self.setup_user(self.audit_user)

        # These query counts were found empirically
        query_counts = [63, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20]
        ordered_course_ids = sorted(
            [str(cid) for cid in (course_ids + [c.id for c in self.courses])])

        self.clear_caches()

        for page in range(1, 12):
            RequestCache.clear_all_namespaces()
            with self.assertNumQueries(query_counts[page - 1]):
                response = self.verify_response(params={
                    'page': page,
                    'page_size': 30
                })

                self.assertIn('results', response.data)
                self.assertEqual(response.data['pagination']['count'], 303)
                self.assertEqual(len(response.data['results']),
                                 30 if page < 11 else 3)
                self.assertEqual([c['id'] for c in response.data['results']],
                                 ordered_course_ids[(page - 1) * 30:page * 30])
Exemple #15
0
def lti_consumer_fields_editing_flag(course_id, enabled_for_course=False):
    """
    Yields CourseEditLTIFieldsEnabledFlag record for unit tests

    Arguments:
        course_id (CourseLocator): course locator to control this feature for.
        enabled_for_course (bool): whether feature is enabled for 'course_id'
    """
    RequestCache.clear_all_namespaces()
    CourseEditLTIFieldsEnabledFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
Exemple #16
0
    def setUp(self):
        super().setUp()
        flag_name = "test_namespace.test_flag"
        self.waffle_flag = WaffleFlag(flag_name, __name__)

        request = RequestFactory().request()
        crum.set_current_request(request)
        RequestCache.clear_all_namespaces()

        self.addCleanup(crum.set_current_request, None)
        self.addCleanup(RequestCache.clear_all_namespaces)
Exemple #17
0
def lti_consumer_fields_editing_flag(course_id, enabled_for_course=False):
    """
    Yields CourseEditLTIFieldsEnabledFlag record for unit tests

    Arguments:
        course_id (CourseLocator): course locator to control this feature for.
        enabled_for_course (bool): whether feature is enabled for 'course_id'
    """
    RequestCache.clear_all_namespaces()
    CourseEditLTIFieldsEnabledFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
Exemple #18
0
    def assert_access_to_gated_content(self, user):
        """
        Verifies access to gated content for the given user is as expected.
        """
        # clear the request cache to flush any cached access results
        RequestCache.clear_all_namespaces()

        # access to gating content (seq1) remains constant
        assert bool(has_access(user, 'load', self.seq1, self.course.id))

        # access to gated content (seq2) remains constant, access is prevented in SeqModule loading
        assert bool(has_access(user, 'load', self.seq2, self.course.id))
    def assert_access_to_gated_content(self, user):
        """
        Verifies access to gated content for the given user is as expected.
        """
        # clear the request cache to flush any cached access results
        RequestCache.clear_all_namespaces()

        # access to gating content (seq1) remains constant
        self.assertTrue(bool(has_access(user, 'load', self.seq1, self.course.id)))

        # access to gated content (seq2) remains constant, access is prevented in SeqModule loading
        self.assertTrue(bool(has_access(user, 'load', self.seq2, self.course.id)))
Exemple #20
0
    def dump_courses_to_neo4j(self,
                              connection_overrides=None,
                              override_cache=False):
        """
        Method that iterates through a list of courses in a modulestore,
        serializes them, then submits tasks to write them to neo4j.
        Arguments:
            connection_overrides (dict): overrides to Neo4j connection
                parameters specified in `settings.COURSEGRAPH_CONNECTION`.
            override_cache: serialize the courses even if they'be been recently
                serialized

        Returns: two lists--one of the courses that were successfully written
            to neo4j and one of courses that were not.
        """

        total_number_of_courses = len(self.course_keys)

        submitted_courses = []
        skipped_courses = []

        graph = authenticate_and_create_graph(connection_overrides)

        for index, course_key in enumerate(self.course_keys):
            # first, clear the request cache to prevent memory leaks
            RequestCache.clear_all_namespaces()

            (needs_dump, reason) = should_dump_course(course_key, graph)
            if not (override_cache or needs_dump):
                log.info("skipping submitting %s, since it hasn't changed",
                         course_key)
                skipped_courses.append(str(course_key))
                continue

            if override_cache:
                reason = "override_cache is True"

            log.info(
                "Now submitting %s for export to neo4j, because %s: course %d of %d total courses",
                course_key,
                reason,
                index + 1,
                total_number_of_courses,
            )

            dump_course_to_neo4j.apply_async(kwargs=dict(
                course_key_string=str(course_key),
                connection_overrides=connection_overrides,
            ))
            submitted_courses.append(str(course_key))

        return submitted_courses, skipped_courses
Exemple #21
0
    def setUp(self):
        super().setUp()
        flag_name = "test_namespace.test_flag"
        self.waffle_flag = WaffleFlag(  # lint-amnesty, pylint: disable=toggle-missing-annotation
            flag_name, __name__
        )

        request = RequestFactory().request()
        crum.set_current_request(request)
        RequestCache.clear_all_namespaces()

        self.addCleanup(crum.set_current_request, None)
        self.addCleanup(RequestCache.clear_all_namespaces)
Exemple #22
0
    def test_caching_site(self):
        site_cfg = SiteConfigurationFactory()
        site_config = ContentTypeGatingConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value is not retrieved from cache after save
        with self.assertNumQueries(1):
            self.assertTrue(ContentTypeGatingConfig.current(site=site_cfg.site).enabled)

        RequestCache.clear_all_namespaces()

        # Check that the site value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(ContentTypeGatingConfig.current(site=site_cfg.site).enabled)

        site_config.enabled = False
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value in cache was deleted on save
        with self.assertNumQueries(1):
            self.assertFalse(ContentTypeGatingConfig.current(site=site_cfg.site).enabled)

        global_config = ContentTypeGatingConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value is not updated in cache by changing the global value
        with self.assertNumQueries(0):
            self.assertFalse(ContentTypeGatingConfig.current(site=site_cfg.site).enabled)
Exemple #23
0
    def test_caching_site(self):
        site_cfg = SiteConfigurationFactory()
        site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value is not retrieved from cache after save
        with self.assertNumQueries(1):
            self.assertTrue(CourseDurationLimitConfig.current(site=site_cfg.site).enabled)

        RequestCache.clear_all_namespaces()

        # Check that the site value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(CourseDurationLimitConfig.current(site=site_cfg.site).enabled)

        site_config.enabled = False
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value in cache was deleted on save
        with self.assertNumQueries(1):
            self.assertFalse(CourseDurationLimitConfig.current(site=site_cfg.site).enabled)

        global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the site value is not updated in cache by changing the global value
        with self.assertNumQueries(0):
            self.assertFalse(CourseDurationLimitConfig.current(site=site_cfg.site).enabled)
    def test_too_many_courses(self):
        """
        Test that search results are limited to 100 courses, and that they don't
        blow up the database.
        """

        ContentTypeGatingConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        CourseDurationLimitConfig.objects.create(
            enabled=True,
            enabled_as_of=datetime(2018, 1, 1),
        )

        course_ids = []

        # Create 300 courses across 30 organizations
        for org_num in range(10):
            org_id = 'org{}'.format(org_num)
            for course_num in range(30):
                course_name = 'course{}.{}'.format(org_num, course_num)
                course_run_name = 'run{}.{}'.format(org_num, course_num)
                course = CourseFactory.create(org=org_id, number=course_name, run=course_run_name, emit_signals=True)
                CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.AUDIT)
                CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.VERIFIED)
                course_ids.append(course.id)

        self.setup_user(self.audit_user)

        # These query counts were found empirically
        query_counts = [63, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20]
        ordered_course_ids = sorted([str(cid) for cid in (course_ids + [c.id for c in self.courses])])

        self.clear_caches()

        for page in range(1, 12):
            RequestCache.clear_all_namespaces()
            with self.assertNumQueries(query_counts[page - 1]):
                response = self.verify_response(params={'page': page, 'page_size': 30})

                self.assertIn('results', response.data)
                self.assertEqual(response.data['pagination']['count'], 303)
                self.assertEqual(len(response.data['results']), 30 if page < 11 else 3)
                self.assertEqual(
                    [c['id'] for c in response.data['results']],
                    ordered_course_ids[(page - 1) * 30:page * 30]
                )
Exemple #25
0
def persistent_grades_feature_flags(global_flag,
                                    enabled_for_all_courses=False,
                                    course_id=None,
                                    enabled_for_course=False):
    """
    Most test cases will use a single call to this manager,
    as they need to set the global setting and the course-specific
    setting for a single course.
    """
    RequestCache.clear_all_namespaces()
    PersistentGradesEnabledFlag.objects.create(
        enabled=global_flag, enabled_for_all_courses=enabled_for_all_courses)
    if course_id:
        CoursePersistentGradesFlag.objects.create(course_id=course_id,
                                                  enabled=enabled_for_course)
    yield
Exemple #26
0
    def test_gradebook(self):
        self.course.enable_ccx = True
        RequestCache.clear_all_namespaces()

        url = reverse(
            'ccx_gradebook',
            kwargs={'course_id': self.ccx_key}
        )
        response = self.client.get(url)
        assert response.status_code == 200
        # Max number of student per page is one.  Patched setting MAX_STUDENTS_PER_PAGE_GRADE_BOOK = 1
        assert len(response.mako_context['students']) == 1
        student_info = response.mako_context['students'][0]
        assert student_info['grade_summary']['percent'] == 0.5
        assert list(student_info['grade_summary']['grade_breakdown'].values())[0]['percent'] == 0.5
        assert len(student_info['grade_summary']['section_breakdown']) == 4
Exemple #27
0
    def clear_caches(cls):
        """
        Clear all of the caches defined in settings.CACHES.
        """
        # N.B. As of 2016-04-20, Django won't return any caches
        # from django.core.cache.caches.all() that haven't been
        # accessed using caches[name] previously, so we loop
        # over our list of overridden caches, instead.
        for cache in settings.CACHES:
            caches[cache].clear()

        # The sites framework caches in a module-level dictionary.
        # Clear that.
        sites.models.SITE_CACHE.clear()

        RequestCache.clear_all_namespaces()
Exemple #28
0
def persistent_grades_feature_flags(
        global_flag,
        enabled_for_all_courses=False,
        course_id=None,
        enabled_for_course=False
):
    """
    Most test cases will use a single call to this manager,
    as they need to set the global setting and the course-specific
    setting for a single course.
    """
    RequestCache.clear_all_namespaces()
    PersistentGradesEnabledFlag.objects.create(enabled=global_flag, enabled_for_all_courses=enabled_for_all_courses)
    if course_id:
        CoursePersistentGradesFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
Exemple #29
0
    def clear_caches(cls):
        """
        Clear all of the caches defined in settings.CACHES.
        """
        # N.B. As of 2016-04-20, Django won't return any caches
        # from django.core.cache.caches.all() that haven't been
        # accessed using caches[name] previously, so we loop
        # over our list of overridden caches, instead.
        for cache in settings.CACHES:
            caches[cache].clear()

        # The sites framework caches in a module-level dictionary.
        # Clear that.
        sites.models.SITE_CACHE.clear()

        RequestCache.clear_all_namespaces()
Exemple #30
0
 def setUp(self):
     """
     Set up test data
     """
     super(ProgramCourseEnrollmentModelTests, self).setUp()
     RequestCache.clear_all_namespaces()
     self.user = UserFactory.create()
     self.program_uuid = uuid4()
     self.program_enrollment = ProgramEnrollment.objects.create(
         user=self.user,
         external_user_key='abc',
         program_uuid=self.program_uuid,
         curriculum_uuid=uuid4(),
         status='enrolled')
     self.course_key = CourseKey.from_string(generate_course_run_key())
     CourseOverviewFactory(id=self.course_key)
Exemple #31
0
 def setUp(self):
     """
     Set up test data
     """
     super(ProgramCourseEnrollmentModelTests, self).setUp()
     RequestCache.clear_all_namespaces()
     self.user = UserFactory(username="******")
     self.program_uuid = UUID("88888888-4444-2222-1111-000000000000")
     self.curriculum_uuid = UUID("77777777-4444-2222-1111-000000000000")
     self.program_enrollment = ProgramEnrollmentFactory(
         user=self.user,
         external_user_key='abc',
         program_uuid=self.program_uuid,
         curriculum_uuid=self.curriculum_uuid,
         status='enrolled')
     self.course_key = CourseKey.from_string("course-v1:blah+blah+blah")
     CourseOverviewFactory(id=self.course_key)
Exemple #32
0
 def setUp(self):
     """
     Set up test data
     """
     super(ProgramCourseEnrollmentModelTests, self).setUp()
     RequestCache.clear_all_namespaces()
     self.user = UserFactory.create()
     self.program_uuid = uuid4()
     self.program_enrollment = ProgramEnrollment.objects.create(
         user=self.user,
         external_user_key='abc',
         program_uuid=self.program_uuid,
         curriculum_uuid=uuid4(),
         status='enrolled'
     )
     self.course_key = CourseKey.from_string(generate_course_run_key())
     CourseOverviewFactory(id=self.course_key)
Exemple #33
0
    def test_request_cached_with_changing_kwargs(self):
        """
        Ensure that calling a decorated function with different keyword arguments
        will not use a cached value invoked by a previous call with different arguments.
        """
        RequestCache.clear_all_namespaces()

        to_be_wrapped = Mock()
        to_be_wrapped.side_effect = [1, 2, 3, 4, 5, 6]
        self.assertEqual(to_be_wrapped.call_count, 0)

        def mock_wrapper(*args, **kwargs):
            """Simple wrapper to let us decorate our mock."""
            return to_be_wrapped(*args, **kwargs)

        wrapped = request_cached(mock_wrapper)

        # This will be a miss, and make an underlying call.
        result = wrapped(1, foo=1)
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        # This will be a miss, and make an underlying call.
        result = wrapped(2, foo=2)
        self.assertEqual(result, 2)
        self.assertEqual(to_be_wrapped.call_count, 2)

        # This is bypass of the decorator.
        direct_result = mock_wrapper(3, foo=3)
        self.assertEqual(direct_result, 3)
        self.assertEqual(to_be_wrapped.call_count, 3)

        # These will be hits, and not make an underlying call.
        result = wrapped(1, foo=1)
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 3)

        result = wrapped(2, foo=2)
        self.assertEqual(result, 2)
        self.assertEqual(to_be_wrapped.call_count, 3)

        # Since we're changing foo, this will be a miss.
        result = wrapped(2, foo=5)
        self.assertEqual(result, 4)
        self.assertEqual(to_be_wrapped.call_count, 4)
Exemple #34
0
    def test_caching_org(self):
        course = CourseOverviewFactory.create(org='test-org')
        site_cfg = SiteConfigurationFactory.create(values={'course_org_filter': course.org})
        org_config = ContentTypeGatingConfig(org=course.org, enabled=True, enabled_as_of=datetime(2018, 1, 1))
        org_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not retrieved from cache after save
        with self.assertNumQueries(2):
            self.assertTrue(ContentTypeGatingConfig.current(org=course.org).enabled)

        RequestCache.clear_all_namespaces()

        # Check that the org value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(ContentTypeGatingConfig.current(org=course.org).enabled)

        org_config.enabled = False
        org_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value in cache was deleted on save
        with self.assertNumQueries(2):
            self.assertFalse(ContentTypeGatingConfig.current(org=course.org).enabled)

        global_config = ContentTypeGatingConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not updated in cache by changing the global value
        with self.assertNumQueries(0):
            self.assertFalse(ContentTypeGatingConfig.current(org=course.org).enabled)

        site_config = ContentTypeGatingConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
        site_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the org value is not updated in cache by changing the site value
        with self.assertNumQueries(0):
            self.assertFalse(ContentTypeGatingConfig.current(org=course.org).enabled)
Exemple #35
0
    def dump_courses_to_neo4j(self, credentials, override_cache=False):
        """
        Method that iterates through a list of courses in a modulestore,
        serializes them, then submits tasks to write them to neo4j.
        Arguments:
            credentials (dict): the necessary credentials to connect
              to neo4j and create a py2neo `Graph` object
            override_cache: serialize the courses even if they'be been recently
                serialized

        Returns: two lists--one of the courses that were successfully written
            to neo4j and one of courses that were not.
        """

        total_number_of_courses = len(self.course_keys)

        submitted_courses = []
        skipped_courses = []

        graph = authenticate_and_create_graph(credentials)

        for index, course_key in enumerate(self.course_keys):
            # first, clear the request cache to prevent memory leaks
            RequestCache.clear_all_namespaces()

            log.info(
                "Now submitting %s for export to neo4j: course %d of %d total courses",
                course_key,
                index + 1,
                total_number_of_courses,
            )

            if not (override_cache or should_dump_course(course_key, graph)):
                log.info("skipping submitting %s, since it hasn't changed", course_key)
                skipped_courses.append(six.text_type(course_key))
                continue

            dump_course_to_neo4j.apply_async(
                args=[six.text_type(course_key), credentials],
            )
            submitted_courses.append(six.text_type(course_key))

        return submitted_courses, skipped_courses
Exemple #36
0
    def dump_courses_to_neo4j(self, credentials, override_cache=False):
        """
        Method that iterates through a list of courses in a modulestore,
        serializes them, then submits tasks to write them to neo4j.
        Arguments:
            credentials (dict): the necessary credentials to connect
              to neo4j and create a py2neo `Graph` object
            override_cache: serialize the courses even if they'be been recently
                serialized

        Returns: two lists--one of the courses that were successfully written
            to neo4j and one of courses that were not.
        """

        total_number_of_courses = len(self.course_keys)

        submitted_courses = []
        skipped_courses = []

        graph = authenticate_and_create_graph(credentials)

        for index, course_key in enumerate(self.course_keys):
            # first, clear the request cache to prevent memory leaks
            RequestCache.clear_all_namespaces()

            log.info(
                "Now submitting %s for export to neo4j: course %d of %d total courses",
                course_key,
                index + 1,
                total_number_of_courses,
            )

            if not (override_cache or should_dump_course(course_key, graph)):
                log.info("skipping submitting %s, since it hasn't changed", course_key)
                skipped_courses.append(six.text_type(course_key))
                continue

            dump_course_to_neo4j.apply_async(
                args=[six.text_type(course_key), credentials],
            )
            submitted_courses.append(six.text_type(course_key))

        return submitted_courses, skipped_courses
Exemple #37
0
    def test_request_cached_with_none_result(self):
        """
        Ensure that calling a decorated function that returns None
        properly caches the result and doesn't recall the underlying
        function.
        """
        RequestCache.clear_all_namespaces()

        to_be_wrapped = Mock()
        to_be_wrapped.side_effect = [None, None, None, 1, 1]
        self.assertEqual(to_be_wrapped.call_count, 0)

        def mock_wrapper(*args, **kwargs):
            """Simple wrapper to let us decorate our mock."""
            return to_be_wrapped(*args, **kwargs)

        wrapped = request_cached(mock_wrapper)

        # This will be a miss, and make an underlying call.
        result = wrapped(1)
        self.assertEqual(result, None)
        self.assertEqual(to_be_wrapped.call_count, 1)

        # This will be a miss, and make an underlying call.
        result = wrapped(2)
        self.assertEqual(result, None)
        self.assertEqual(to_be_wrapped.call_count, 2)

        # This is bypass of the decorator.
        direct_result = mock_wrapper(3)
        self.assertEqual(direct_result, None)
        self.assertEqual(to_be_wrapped.call_count, 3)

        # These will be hits, and not make an underlying call.
        result = wrapped(1)
        self.assertEqual(result, None)
        self.assertEqual(to_be_wrapped.call_count, 3)

        result = wrapped(2)
        self.assertEqual(result, None)
        self.assertEqual(to_be_wrapped.call_count, 3)
    def test_authenticated_user_found_is_properly_reset(
            self, mock_set_custom_attribute):
        # set user before process_request
        self.request.user = UserFactory()
        self.middleware.process_request(self.request)
        self.middleware.process_response(self.request, None)

        mock_set_custom_attribute.assert_any_call(
            'request_authenticated_user_found_in_middleware',
            'process_request')

        # set up new request and set user before process_response
        mock_set_custom_attribute.reset_mock()
        RequestCache.clear_all_namespaces()
        self.request = RequestFactory().get('/')
        self.request.user = UserFactory()
        self.middleware.process_response(self.request, None)

        mock_set_custom_attribute.assert_any_call(
            'request_authenticated_user_found_in_middleware',
            'process_response')
Exemple #39
0
    def test_request_cached_mixed_unicode_str_args(self):
        """
        Ensure that request_cached can work with mixed str and Unicode parameters.
        """
        RequestCache.clear_all_namespaces()

        def dummy_function(arg1, arg2):
            """
            A dummy function that expects an str and unicode arguments.
            """
            assert isinstance(arg1, str), 'First parameter has to be of type `str`'
            assert isinstance(arg2, unicode), 'Second parameter has to be of type `unicode`'
            return True

        self.assertTrue(dummy_function('Hello', u'World'), 'Should be callable with ASCII chars')
        self.assertTrue(dummy_function('H∂llå', u'Wørld'), 'Should be callable with non-ASCII chars')

        wrapped = request_cached(dummy_function)

        self.assertTrue(wrapped('Hello', u'World'), 'Wrapper should handle ASCII only chars')
        self.assertTrue(wrapped('H∂llå', u'Wørld'), 'Wrapper should handle non-ASCII chars')
Exemple #40
0
    def test_grades_csv(self):
        self.course.enable_ccx = True
        RequestCache.clear_all_namespaces()

        url = reverse(
            'ccx_grades_csv',
            kwargs={'course_id': self.ccx_key}
        )
        response = self.client.get(url)
        assert response.status_code == 200
        # Are the grades downloaded as an attachment?
        assert response['content-disposition'] == 'attachment'
        rows = response.content.decode('utf-8').strip().split('\r')
        headers = rows[0]
        # picking first student records
        data = dict(list(zip(headers.strip().split(','), rows[1].strip().split(','))))
        assert 'HW 04' not in data
        assert data['HW 01'] == '0.75'
        assert data['HW 02'] == '0.5'
        assert data['HW 03'] == '0.25'
        assert data['HW Avg'] == '0.5'
Exemple #41
0
    def test_caching_global(self):
        global_config = ContentTypeGatingConfig(enabled=True,
                                                enabled_as_of=datetime(
                                                    2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value is not retrieved from cache after save
        with self.assertNumQueries(1):
            assert ContentTypeGatingConfig.current().enabled

        RequestCache.clear_all_namespaces()

        # Check that the global value can be retrieved from cache after read
        with self.assertNumQueries(0):
            assert ContentTypeGatingConfig.current().enabled

        global_config.enabled = False
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value in cache was deleted on save
        with self.assertNumQueries(1):
            assert not ContentTypeGatingConfig.current().enabled
Exemple #42
0
    def test_caching_global(self):
        global_config = CourseDurationLimitConfig(enabled=True,
                                                  enabled_as_of=datetime(
                                                      2018,
                                                      1,
                                                      1,
                                                      tzinfo=pytz.UTC))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value is not retrieved from cache after save
        with self.assertNumQueries(1):
            self.assertTrue(CourseDurationLimitConfig.current().enabled)

        RequestCache.clear_all_namespaces()

        # Check that the global value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(CourseDurationLimitConfig.current().enabled)

        global_config.enabled = False
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value in cache was deleted on save
        with self.assertNumQueries(1):
            self.assertFalse(CourseDurationLimitConfig.current().enabled)
Exemple #43
0
    def test_request_context_caching(self):
        """
        Test that the RequestContext is cached in the RequestCache.
        """
        with patch('edxmako.request_context.get_current_request', return_value=None):
            # requestcontext should be None, because the cache isn't filled
            self.assertIsNone(get_template_request_context())

        with patch('edxmako.request_context.get_current_request', return_value=self.request):
            # requestcontext should not be None, and should fill the cache
            self.assertIsNotNone(get_template_request_context())

        mock_get_current_request = Mock()
        with patch('edxmako.request_context.get_current_request', mock_get_current_request):
            # requestcontext should not be None, because the cache is filled
            self.assertIsNotNone(get_template_request_context())
        mock_get_current_request.assert_not_called()

        RequestCache.clear_all_namespaces()

        with patch('edxmako.request_context.get_current_request', return_value=None):
            # requestcontext should be None, because the cache isn't filled
            self.assertIsNone(get_template_request_context())
Exemple #44
0
    def test_caching_global(self):
        global_config = ContentTypeGatingConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value is not retrieved from cache after save
        with self.assertNumQueries(1):
            self.assertTrue(ContentTypeGatingConfig.current().enabled)

        RequestCache.clear_all_namespaces()

        # Check that the global value can be retrieved from cache after read
        with self.assertNumQueries(0):
            self.assertTrue(ContentTypeGatingConfig.current().enabled)

        global_config.enabled = False
        global_config.save()

        RequestCache.clear_all_namespaces()

        # Check that the global value in cache was deleted on save
        with self.assertNumQueries(1):
            self.assertFalse(ContentTypeGatingConfig.current().enabled)
Exemple #45
0
 def setUp(self):
     super(SocialAuthEnrollmentCompletionSignalTest, self).setUp()
     RequestCache.clear_all_namespaces()
     catalog_org = CatalogOrganizationFactory.create(key=self.organization.short_name)
     self.program_uuid = self._create_catalog_program(catalog_org)['uuid']
 def setUp(self):
     super(TestCourseWaffleFlag, self).setUp()
     request = RequestFactory().request()
     self.addCleanup(crum.set_current_request, None)
     crum.set_current_request(request)
     RequestCache.clear_all_namespaces()
 def setUp(self):
     RequestCache.clear_all_namespaces()