From 62775c891ae10aa6e5a5b18b7d0e1799d45ffefe Mon Sep 17 00:00:00 2001 From: Gregory Martin Date: Tue, 3 Apr 2018 11:12:35 -0400 Subject: [PATCH] Delete visual_progress_enabled waffle flag. https://openedx.atlassian.net/browse/EDUCATOR-2333 --- common/djangoapps/student/tests/test_views.py | 6 +- common/lib/xmodule/xmodule/seq_module.py | 7 +- .../xmodule/xmodule/tests/test_sequence.py | 16 ---- .../tests/lms/test_lms_course_home.py | 10 -- .../user_api/accounts/tests/test_utils.py | 3 +- .../course-outline-fragment-new.html | 6 +- .../tests/views/test_course_outline.py | 96 +++++++------------ openedx/features/course_experience/utils.py | 14 +-- .../course_experience/views/course_outline.py | 9 +- .../completion_integration/test_waffle.py | 79 --------------- requirements/edx/base.txt | 2 +- 11 files changed, 48 insertions(+), 200 deletions(-) delete mode 100644 openedx/tests/completion_integration/test_waffle.py diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index ed841fd031..96fe986e2a 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -720,8 +720,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, submit_completions_for_testing(self.user, course_key, block_keys) - with patch('completion.utilities.visual_progress_enabled', return_value=True): - response = self.client.get(reverse('dashboard')) + response = self.client.get(reverse('dashboard')) course_key_string = str(course_key) resume_block_key_string = str(block_keys[-1]) @@ -808,8 +807,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, ) ) - with patch('completion.utilities.visual_progress_enabled', return_value=True): - response = self.client.get(reverse('dashboard')) + response = self.client.get(reverse('dashboard')) html_for_view_buttons = [ self._remove_whitespace_from_html_string(button) diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 751a895fae..8f7320381c 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -210,8 +210,6 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): if dispatch == 'get_completion': completion_service = self.runtime.service(self, 'completion') - if not completion_service.visual_progress_enabled(): - return None usage_key = data.get('usage_key', None) item = self.get_child(UsageKey.from_string(usage_key)) @@ -472,8 +470,9 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): 'path': " > ".join(display_names + [item.display_name_with_default]), } - if is_user_authenticated and completion_service.visual_progress_enabled(): - iteminfo['complete'] = completion_service.vertical_is_complete(item) + if is_user_authenticated: + if item.location.block_type == 'vertical': + iteminfo['complete'] = completion_service.vertical_is_complete(item) contents.append(iteminfo) diff --git a/common/lib/xmodule/xmodule/tests/test_sequence.py b/common/lib/xmodule/xmodule/tests/test_sequence.py index fbc6281000..67d46a3ae3 100644 --- a/common/lib/xmodule/xmodule/tests/test_sequence.py +++ b/common/lib/xmodule/xmodule/tests/test_sequence.py @@ -280,22 +280,6 @@ class SequenceBlockTestCase(XModuleXmlImportTest): # assert content shown as normal self._assert_ungated(html, self.sequence_1_2) - def test_handle_ajax_get_completion_disabled(self): - """ - Test when completion service is turned off by waffle, the ajax call returns correct - None value - """ - completion_waffle_mock = Mock() - completion_waffle_mock.return_value.visual_progress_enabled.return_value = False - self.sequence_3_1.xmodule_runtime._services['completion'] = completion_waffle_mock # pylint: disable=protected-access - for child in self.sequence_3_1.get_children(): - usage_key = unicode(child.location) - completion_return = self.sequence_3_1.handle_ajax( - 'get_completion', - {'usage_key': usage_key} - ) - self.assertIs(completion_return, None) - def test_handle_ajax_get_completion_success(self): """ Test that the completion data is returned successfully on diff --git a/common/test/acceptance/tests/lms/test_lms_course_home.py b/common/test/acceptance/tests/lms/test_lms_course_home.py index 82545527d7..65b2cbec7b 100644 --- a/common/test/acceptance/tests/lms/test_lms_course_home.py +++ b/common/test/acceptance/tests/lms/test_lms_course_home.py @@ -124,16 +124,6 @@ class CourseHomeTest(CourseHomeBaseTest): bookmarks_page = BookmarksPage(self.browser, self.course_id) self.assertTrue(bookmarks_page.is_browser_on_page()) - # Test "Resume Course" button from header - self.course_home_page.visit() - self.course_home_page.resume_course_from_header() - self.assertTrue(self.courseware_page.nav.is_on_section('Test Section 2', 'Test Subsection 3')) - - # Test "Resume Course" button from within outline - self.course_home_page.visit() - self.course_home_page.outline.resume_course_from_outline() - self.assertTrue(self.courseware_page.nav.is_on_section('Test Section 2', 'Test Subsection 3')) - @attr('a11y') class CourseHomeA11yTest(CourseHomeBaseTest): diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py b/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py index 94e39bd7bc..ec8cf1f1e9 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py @@ -113,9 +113,8 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix ) @override_settings(LMS_ROOT_URL='test_url:9999') - @patch('completion.waffle.get_current_site') @ddt.data(True, False) - def test_retrieve_last_sitewide_block_completed(self, use_username, get_patched_current_site): # pylint: disable=unused-argument + def test_retrieve_last_sitewide_block_completed(self, use_username): """ Test that the method returns a URL for the "last completed" block when sending a user object diff --git a/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html b/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html index 23ec168a42..3d596f174a 100644 --- a/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html +++ b/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html @@ -37,7 +37,7 @@ from openedx.core.djangolib.markup import HTML, Text id="${ section['id'] }">

${ section['display_name'] }

- % if show_visual_progress and section.get('complete'): + % if section.get('complete'): % endif @@ -83,7 +83,7 @@ from openedx.core.djangolib.markup import HTML, Text ${ subsection['display_name'] } - % if subsection.get('complete') and show_visual_progress: + % if subsection.get('complete'): % endif % endif @@ -168,7 +168,7 @@ from openedx.core.djangolib.markup import HTML, Text ${ vertical['display_name'] } - % if vertical.get('complete') and show_visual_progress: + % if vertical.get('complete'): % endif diff --git a/openedx/features/course_experience/tests/views/test_course_outline.py b/openedx/features/course_experience/tests/views/test_course_outline.py index ac734e42f8..28d43c2044 100644 --- a/openedx/features/course_experience/tests/views/test_course_outline.py +++ b/openedx/features/course_experience/tests/views/test_course_outline.py @@ -307,11 +307,6 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT cls.user = UserFactory(password=TEST_PASSWORD) CourseEnrollment.enroll(cls.user, cls.course.id) cls.site = Site.objects.get_current() - SiteConfiguration.objects.get_or_create( - site=cls.site, - enabled=True, - values={waffle.ENABLE_SITE_VISUAL_PROGRESS: True} - ) @classmethod def create_test_course(cls): @@ -354,6 +349,27 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT ) self.assertEqual(200, self.client.get(last_accessed_url).status_code) + @override_switch( + '{}.{}'.format( + waffle.WAFFLE_NAMESPACE, waffle.ENABLE_COMPLETION_TRACKING + ), + active=True + ) + def complete_sequential(self, course, sequential): + """ + Completes provided sequential. + """ + course_key = CourseKey.from_string(str(course.id)) + # Fake a visit to sequence2/vertical2 + block_key = UsageKey.from_string(unicode(sequential.location)) + completion = 1.0 + BlockCompletion.objects.submit_completion( + user=self.user, + course_key=course_key, + block_key=block_key, + completion=completion + ) + def visit_course_home(self, course, start_count=0, resume_count=0): """ Helper function to navigates to course home page, test for resume buttons @@ -384,37 +400,12 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT self.assertTrue(content('.action-resume-course').attr('href').endswith('/course/' + course.url_name)) - def test_resume_course(self): - """ - Tests that two resume course buttons appear when the course has been accessed. - """ - course = self.course - - # first navigate to a sequential to make it the last accessed - chapter = course.children[0] - sequential = chapter.children[0] - vertical = sequential.children[0] - self.visit_sequential(course, chapter, sequential) - - # check resume course buttons - response = self.visit_course_home(course, resume_count=2) - content = pq(response.content) - self.assertTrue(content('.action-resume-course').attr('href').endswith('/vertical/' + vertical.url_name)) - - @override_switch( - '{}.{}'.format( - waffle.WAFFLE_NAMESPACE, waffle.ENABLE_VISUAL_PROGRESS - ), - active=True - ) @override_settings(LMS_BASE='test_url:9999') - @patch('completion.waffle.get_current_site') - def test_resume_course_with_completion_api(self, get_patched_current_site): + def test_resume_course_with_completion_api(self): """ Tests completion API resume button functionality """ self.override_waffle_switch(True) - get_patched_current_site.return_value = self.site # Course tree course = self.course @@ -422,16 +413,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT vertical1 = course.children[0].children[0].children[0] vertical2 = course.children[0].children[1].children[0] - # Fake a visit to sequence1/vertical1 - block_key = UsageKey.from_string(unicode(vertical1.location)) - completion = 1.0 - BlockCompletion.objects.submit_completion( - user=self.user, - course_key=course_key, - block_key=block_key, - completion=completion - ) - + self.complete_sequential(self.course, vertical1) # Test for 'resume' link response = self.visit_course_home(course, resume_count=2) @@ -439,15 +421,8 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT content = pq(response.content) self.assertTrue(content('.action-resume-course').attr('href').endswith('/vertical/' + vertical1.url_name)) - # Fake a visit to sequence2/vertical2 - block_key = UsageKey.from_string(unicode(vertical2.location)) - completion = 1.0 - BlockCompletion.objects.submit_completion( - user=self.user, - course_key=course_key, - block_key=block_key, - completion=completion - ) + self.complete_sequential(self.course, vertical2) + # Test for 'resume' link response = self.visit_course_home(course, resume_count=2) # Test for 'resume' link URL - should be vertical 2 @@ -465,7 +440,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT def test_resume_course_deleted_sequential(self): """ - Tests resume course when the last accessed sequential is deleted and + Tests resume course when the last completed sequential is deleted and there is another sequential in the vertical. """ @@ -476,7 +451,8 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT self.assertGreaterEqual(len(chapter.children), 2) sequential = chapter.children[0] sequential2 = chapter.children[1] - self.visit_sequential(course, chapter, sequential) + self.complete_sequential(course, sequential) + self.complete_sequential(course, sequential2) # remove one of the sequentials from the chapter with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id): @@ -490,7 +466,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT def test_resume_course_deleted_sequentials(self): """ - Tests resume course when the last accessed sequential is deleted and + Tests resume course when the last completed sequential is deleted and there are no sequentials left in the vertical. """ @@ -500,7 +476,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT chapter = course.children[0] self.assertEqual(len(chapter.children), 2) sequential = chapter.children[0] - self.visit_sequential(course, chapter, sequential) + self.complete_sequential(course, sequential) # remove all sequentials from chapter with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id): @@ -508,22 +484,14 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT self.store.delete_item(sequential.location, self.user.id) # check resume course buttons - self.visit_course_home(course, resume_count=1) + self.visit_course_home(course, start_count=1, resume_count=0) - @override_switch( - '{}.{}'.format( - waffle.WAFFLE_NAMESPACE, waffle.ENABLE_VISUAL_PROGRESS - ), - active=True - ) - @patch('completion.waffle.get_current_site') - def test_course_home_for_global_staff(self, get_patched_current_site): + def test_course_home_for_global_staff(self): """ Tests that staff user can access the course home without being enrolled in the course. """ course = self.course - get_patched_current_site.return_value = self.site self.user.is_staff = True self.user.save() diff --git a/openedx/features/course_experience/utils.py b/openedx/features/course_experience/utils.py index 50467714e8..3870588800 100644 --- a/openedx/features/course_experience/utils.py +++ b/openedx/features/course_experience/utils.py @@ -2,7 +2,6 @@ Common utilities for the course experience, including course outline. """ from completion.models import BlockCompletion -from completion.waffle import visual_progress_enabled from lms.djangoapps.course_api.blocks.api import get_blocks from lms.djangoapps.course_blocks.utils import get_student_module_as_dict @@ -154,14 +153,11 @@ def get_course_outline_block_tree(request, course_id): populate_children(course_outline_root_block, all_blocks['blocks']) set_last_accessed_default(course_outline_root_block) - if visual_progress_enabled(course_key=course_key): - mark_blocks_completed( - block=course_outline_root_block, - user=request.user, - course_key=course_key - ) - else: - mark_last_accessed(request.user, course_key, course_outline_root_block) + mark_blocks_completed( + block=course_outline_root_block, + user=request.user, + course_key=course_key + ) return course_outline_root_block diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index cd12fd97f0..d404813659 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -43,18 +43,11 @@ class CourseOutlineFragmentView(EdxFragmentView): if not course_block_tree: return None - # TODO: EDUCATOR-2283 Remove 'show_visual_progress' from context - # and remove the check for it in the HTML file - show_visual_progress = ( - completion_waffle.visual_progress_enabled(course_key) and - self.user_enrolled_after_completion_collection(request.user, course_key) - ) context = { 'csrf': csrf(request)['csrf_token'], 'course': course_overview, - 'blocks': course_block_tree, - 'show_visual_progress': show_visual_progress, 'due_date_display_format': course.due_date_display_format, + 'blocks': course_block_tree } # TODO: EDUCATOR-2283 Remove this check when the waffle flag is turned on in production diff --git a/openedx/tests/completion_integration/test_waffle.py b/openedx/tests/completion_integration/test_waffle.py deleted file mode 100644 index 963009896a..0000000000 --- a/openedx/tests/completion_integration/test_waffle.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Tests waffle mechanics and feature-gating for block completion features. -""" - -from __future__ import absolute_import, unicode_literals - -from completion import waffle -import ddt -from django.test import TestCase -import mock -from opaque_keys.edx.keys import CourseKey - -from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory, SiteConfigurationFactory -from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag -from openedx.core.djangolib.testing.utils import skip_unless_lms - - -@skip_unless_lms -@ddt.ddt -class FeatureGatingTests(TestCase): - """ - Tests the logic of the completion feature-gating functions in the LMS. - """ - def setUp(self): - self.site = SiteFactory.create() - self.site_patcher = mock.patch('completion.waffle.get_current_site') - mocked_current_site = self.site_patcher.start() - mocked_current_site.return_value = self.site - - self.course_key = CourseKey.from_string('course-v1:edX+DemoX+Demo_Course') - - def tearDown(self): - self.site_patcher.stop() - - def _make_site_config(self, enable_feature): - site_config = SiteConfigurationFactory.create(site=self.site) - site_config.values[waffle.ENABLE_SITE_VISUAL_PROGRESS] = enable_feature - site_config.save() - - def test_site_disables_visual_progress_no_config(self): - assert waffle.site_disables_visual_progress() is False - - @ddt.data(True, False) - def test_site_disables_visual_progress_with_config(self, config_value): - self._make_site_config(config_value) - assert (not config_value) == waffle.site_disables_visual_progress() - - def test_visual_progress_gating_tracking_disabled(self): - with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, False): - assert waffle.visual_progress_enabled(self.course_key) is False - - def test_visual_progress_gating_site_disabled(self): - self._make_site_config(False) - assert waffle.visual_progress_enabled(self.course_key) is False - - def test_visual_progress_gating_course_disabled(self): - self._make_site_config(True) - with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True): - with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, False): - with override_waffle_flag(waffle.waffle_flag(), active=False): - assert waffle.visual_progress_enabled(self.course_key) is False - - def test_visual_progress_happy_path_no_site_config(self): - with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True): - with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, True): - assert waffle.visual_progress_enabled(self.course_key) is True - - def test_visual_progress_happy_path_with_site_config(self): - self._make_site_config(True) - with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True): - with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, True): - assert waffle.visual_progress_enabled(self.course_key) is True - - def test_visual_progress_happy_path_visual_switch_disabled(self): - self._make_site_config(True) - with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True): - with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, False): - with override_waffle_flag(waffle.waffle_flag(), active=True): - assert waffle.visual_progress_enabled(self.course_key) is True diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index d143013ffb..c61145cb34 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -54,7 +54,7 @@ edx-lint==0.5.4 git+https://github.com/cpennington/pylint-django@fix-field-inference-during-monkey-patching#egg=pylint-django==0.0 enum34==1.1.6 -edx-completion==0.1.4 +edx-completion==0.1.5 edx-django-oauth2-provider==1.2.5 edx-django-sites-extensions==2.3.1 edx-enterprise==0.67.3