Skip to content

Commit 213590b

Browse files
authored
Merge branch 'master' into fix/remove-nonfunctional-retirement-code
2 parents 990d6a9 + cb86181 commit 213590b

34 files changed

Lines changed: 1673 additions & 187 deletions

lms/djangoapps/bulk_email/tests/test_course_optout.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,25 @@
1313
from edx_ace.message import Message
1414
from edx_ace.policy import PolicyResult
1515
from edx_ace.recipient import Recipient
16+
from edx_toggles.toggles.testutils import override_waffle_flag
1617

1718
from common.djangoapps.student.models import CourseEnrollment
1819
from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
1920
from lms.djangoapps.bulk_email.api import get_unsubscribed_link
2021
from lms.djangoapps.bulk_email.models import BulkEmailFlag
2122
from lms.djangoapps.bulk_email.policies import CourseEmailOptout
23+
from lms.djangoapps.instructor.toggles import LEGACY_INSTRUCTOR_DASHBOARD
2224
from xmodule.modulestore.tests.django_utils import (
2325
ModuleStoreTestCase, # lint-amnesty, pylint: disable=wrong-import-order
2426
)
2527
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
2628

2729

2830
@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) # lint-amnesty, pylint: disable=line-too-long
31+
# Tests for legacy views. When DEPR-38432 is picked up, these tests will require the following changes:
32+
# Either remove or leave the specific parts that reference the legacy instructor dashboard,
33+
# and remove the override_waffle_flag for LEGACY_INSTRUCTOR_DASHBOARD.
34+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
2935
class TestOptoutCourseEmails(ModuleStoreTestCase):
3036
"""
3137
Test that optouts are referenced in sending course email.

lms/djangoapps/bulk_email/tests/test_email.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from django.test.utils import override_settings
1717
from django.urls import reverse
1818
from django.utils.translation import get_language
19+
from edx_toggles.toggles.testutils import override_waffle_flag
1920
from markupsafe import escape
2021

2122
from common.djangoapps.course_modes.models import CourseMode
@@ -29,6 +30,7 @@
2930
)
3031
from lms.djangoapps.bulk_email.messages import ACEEmail
3132
from lms.djangoapps.bulk_email.tasks import _get_course_email_context, _get_source_address
33+
from lms.djangoapps.instructor.toggles import LEGACY_INSTRUCTOR_DASHBOARD
3234
from lms.djangoapps.instructor_task.subtasks import update_subtask_status
3335
from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort
3436
from openedx.core.djangoapps.course_groups.models import CourseCohort
@@ -62,6 +64,10 @@ def mock_update_subtask_status(entry_id, current_task_id, new_subtask_status):
6264
return mock_update_subtask_status
6365

6466

67+
# Tests for legacy views. When DEPR-38432 is picked up, these tests will require the following changes:
68+
# Either remove or leave the specific parts that reference the legacy instructor dashboard,
69+
# and remove the override_waffle_flag for LEGACY_INSTRUCTOR_DASHBOARD.
70+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
6571
class EmailSendFromDashboardTestCase(SharedModuleStoreTestCase):
6672
"""
6773
Test that emails send correctly.

lms/djangoapps/bulk_email/tests/test_signals.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,25 @@
99
from django.core import mail
1010
from django.core.management import call_command
1111
from django.urls import reverse
12+
from edx_toggles.toggles.testutils import override_waffle_flag
1213
from opaque_keys.edx.keys import CourseKey
1314

1415
from common.djangoapps.student.models import CourseEnrollment
1516
from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
1617
from lms.djangoapps.bulk_email.models import BulkEmailFlag, Optout
1718
from lms.djangoapps.bulk_email.signals import force_optout_all
19+
from lms.djangoapps.instructor.toggles import LEGACY_INSTRUCTOR_DASHBOARD
1820
from xmodule.modulestore.tests.django_utils import (
1921
ModuleStoreTestCase, # lint-amnesty, pylint: disable=wrong-import-order
2022
)
2123
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
2224

2325

2426
@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) # lint-amnesty, pylint: disable=line-too-long
27+
# Tests for legacy views. When DEPR-38432 is picked up, these tests will require the following changes:
28+
# Either remove or leave the specific parts that reference the legacy instructor dashboard,
29+
# and remove the override_waffle_flag for LEGACY_INSTRUCTOR_DASHBOARD.
30+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
2531
class TestOptoutCourseEmailsBySignal(ModuleStoreTestCase):
2632
"""
2733
Tests that the force_optout_all signal receiver opts the user out of course emails

lms/djangoapps/courseware/tests/test_view_authentication.py

Lines changed: 193 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pytz
1010
from django.urls import reverse
11+
from edx_toggles.toggles.testutils import override_waffle_flag
1112

1213
from common.djangoapps.student.tests.factories import (
1314
BetaTesterFactory,
@@ -21,6 +22,7 @@
2122
)
2223
from lms.djangoapps.courseware.access import has_access
2324
from lms.djangoapps.courseware.tests.helpers import CourseAccessTestMixin, LoginEnrollmentTestCase
25+
from lms.djangoapps.instructor.toggles import LEGACY_INSTRUCTOR_DASHBOARD
2426
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
2527
from xmodule.modulestore.django import modulestore
2628
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
@@ -92,7 +94,11 @@ def _check_staff(self, course):
9294
for index in range(len(course.textbooks))
9395
])
9496
for url in urls:
95-
self.assert_request_status_code(200, url)
97+
# Instructor dashboard returns 302 (MFE redirect) by default
98+
if 'instructor' in url:
99+
self.assert_request_status_code(302, url)
100+
else:
101+
self.assert_request_status_code(200, url)
96102

97103
# The student progress tab is not accessible to a student
98104
# before launch, so the instructor view-as-student feature
@@ -109,6 +115,58 @@ def _check_staff(self, course):
109115
)
110116
self.assert_request_status_code(302, url)
111117

118+
def _check_staff_legacy(self, course):
119+
"""
120+
Check that access is right for staff in course with legacy instructor dashboard enabled.
121+
"""
122+
names = ['about_course', 'instructor_dashboard', 'progress']
123+
urls = self._reverse_urls(names, course)
124+
urls.extend([
125+
reverse('book', kwargs={'course_id': str(course.id),
126+
'book_index': index})
127+
for index in range(len(course.textbooks))
128+
])
129+
for url in urls:
130+
# With legacy flag enabled, all URLs return 200 (instructor dashboard skips MFE redirect)
131+
self.assert_request_status_code(200, url)
132+
133+
# The student progress tab behavior is affected by legacy flag in normal scenarios
134+
url = reverse(
135+
'student_progress',
136+
kwargs={
137+
'course_id': str(course.id),
138+
'student_id': self.enrolled_user.id,
139+
}
140+
)
141+
self.assert_request_status_code(200, url)
142+
143+
def _check_staff_legacy_dark_launch(self, course):
144+
"""
145+
Check staff access during dark launch with legacy instructor dashboard enabled.
146+
In dark launch scenarios, student progress URL still returns 302 even with legacy flag.
147+
"""
148+
names = ['about_course', 'instructor_dashboard', 'progress']
149+
urls = self._reverse_urls(names, course)
150+
urls.extend([
151+
reverse('book', kwargs={'course_id': str(course.id),
152+
'book_index': index})
153+
for index in range(len(course.textbooks))
154+
])
155+
for url in urls:
156+
# With legacy flag enabled, all URLs return 200 (instructor dashboard skips MFE redirect)
157+
self.assert_request_status_code(200, url)
158+
159+
# In dark launch scenarios, student progress URL still returns 302 even with legacy flag
160+
# because course access restrictions take precedence
161+
url = reverse(
162+
'student_progress',
163+
kwargs={
164+
'course_id': str(course.id),
165+
'student_id': self.enrolled_user.id,
166+
}
167+
)
168+
self.assert_request_status_code(302, url)
169+
112170
def login(self, user): # lint-amnesty, pylint: disable=arguments-differ
113171
return super().login(user.email, self.TEST_PASSWORD)
114172

@@ -186,7 +244,7 @@ def test_staff_course_access(self):
186244

187245
# Now should be able to get to self.course, but not self.test_course
188246
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
189-
self.assert_request_status_code(200, url)
247+
self.assert_request_status_code(302, url)
190248

191249
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
192250
self.assert_request_status_code(404, url)
@@ -200,7 +258,7 @@ def test_instructor_course_access(self):
200258

201259
# Now should be able to get to self.course, but not self.test_course
202260
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
203-
self.assert_request_status_code(200, url)
261+
self.assert_request_status_code(302, url)
204262

205263
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
206264
self.assert_request_status_code(404, url)
@@ -212,10 +270,10 @@ def test_org_staff_access(self):
212270
"""
213271
self.login(self.org_staff_user)
214272
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
215-
self.assert_request_status_code(200, url)
273+
self.assert_request_status_code(302, url)
216274

217275
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
218-
self.assert_request_status_code(200, url)
276+
self.assert_request_status_code(302, url)
219277

220278
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.other_org_course.id)})
221279
self.assert_request_status_code(404, url)
@@ -227,10 +285,10 @@ def test_org_instructor_access(self):
227285
"""
228286
self.login(self.org_instructor_user)
229287
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
230-
self.assert_request_status_code(200, url)
288+
self.assert_request_status_code(302, url)
231289

232290
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
233-
self.assert_request_status_code(200, url)
291+
self.assert_request_status_code(302, url)
234292

235293
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.other_org_course.id)})
236294
self.assert_request_status_code(404, url)
@@ -242,12 +300,94 @@ def test_global_staff_access(self):
242300
self.login(self.global_staff_user)
243301

244302
# and now should be able to load both
303+
urls = [reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)}),
304+
reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})]
305+
306+
for url in urls:
307+
self.assert_request_status_code(302, url)
308+
309+
# Legacy instructor dashboard tests (with waffle flag enabled, expect 200 responses)
310+
311+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
312+
def test_staff_course_access_legacy(self):
313+
"""
314+
Verify staff can load the legacy instructor dashboard (expects 200 response).
315+
"""
316+
self.login(self.staff_user)
317+
318+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
319+
self.assert_request_status_code(200, url)
320+
321+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
322+
self.assert_request_status_code(404, url)
323+
324+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
325+
def test_instructor_course_access_legacy(self):
326+
"""
327+
Verify instructor can load the legacy instructor dashboard (expects 200 response).
328+
"""
329+
self.login(self.instructor_user)
330+
331+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
332+
self.assert_request_status_code(200, url)
333+
334+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
335+
self.assert_request_status_code(404, url)
336+
337+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
338+
def test_org_staff_access_legacy(self):
339+
"""
340+
Verify org staff can load the legacy instructor dashboard (expects 200 response).
341+
"""
342+
self.login(self.org_staff_user)
343+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
344+
self.assert_request_status_code(200, url)
345+
346+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
347+
self.assert_request_status_code(200, url)
348+
349+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.other_org_course.id)})
350+
self.assert_request_status_code(404, url)
351+
352+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
353+
def test_org_instructor_access_legacy(self):
354+
"""
355+
Verify org instructor can load the legacy instructor dashboard (expects 200 response).
356+
"""
357+
self.login(self.org_instructor_user)
358+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)})
359+
self.assert_request_status_code(200, url)
360+
361+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})
362+
self.assert_request_status_code(200, url)
363+
364+
url = reverse('instructor_dashboard', kwargs={'course_id': str(self.other_org_course.id)})
365+
self.assert_request_status_code(404, url)
366+
367+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
368+
def test_global_staff_access_legacy(self):
369+
"""
370+
Verify the global staff user can access the legacy instructor dashboard (expects 200 response).
371+
"""
372+
self.login(self.global_staff_user)
373+
245374
urls = [reverse('instructor_dashboard', kwargs={'course_id': str(self.course.id)}),
246375
reverse('instructor_dashboard', kwargs={'course_id': str(self.test_course.id)})]
247376

248377
for url in urls:
249378
self.assert_request_status_code(200, url)
250379

380+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
381+
def test_staff_method_legacy(self):
382+
"""
383+
Test the _check_staff_legacy helper method with legacy flag enabled (expects 200 response).
384+
"""
385+
self.login(self.staff_user)
386+
self.enroll(self.course, True)
387+
388+
# Test the _check_staff_legacy method which includes instructor dashboard checks
389+
self._check_staff_legacy(self.course)
390+
251391
@patch.dict('lms.djangoapps.courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
252392
def test_dark_launch_enrolled_student(self):
253393
"""
@@ -355,6 +495,52 @@ def test_enrollment_period(self):
355495
self.login(self.global_staff_user)
356496
assert self.enroll(self.course)
357497

498+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
499+
@patch.dict('lms.djangoapps.courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
500+
def test_dark_launch_instructor_legacy(self):
501+
"""
502+
Make sure that before course start instructors can access the
503+
page for their course with legacy instructor dashboard enabled.
504+
"""
505+
now = datetime.datetime.now(pytz.UTC)
506+
tomorrow = now + datetime.timedelta(days=1)
507+
self.course.start = tomorrow
508+
self.test_course.start = tomorrow
509+
self.course = self.update_course(self.course, self.user.id)
510+
self.test_course = self.update_course(self.test_course, self.user.id)
511+
512+
self.login(self.instructor_user)
513+
# Enroll in the classes---can't see courseware otherwise.
514+
self.enroll(self.course, True)
515+
self.enroll(self.test_course, True)
516+
517+
# should now be able to get to everything for self.course
518+
self._check_staff_legacy_dark_launch(self.course)
519+
self._check_non_staff_dark(self.test_course)
520+
521+
@override_waffle_flag(LEGACY_INSTRUCTOR_DASHBOARD, active=True)
522+
@patch.dict('lms.djangoapps.courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
523+
def test_dark_launch_global_staff_legacy(self):
524+
"""
525+
Make sure that before course start staff can access
526+
course pages with legacy instructor dashboard enabled.
527+
"""
528+
now = datetime.datetime.now(pytz.UTC)
529+
tomorrow = now + datetime.timedelta(days=1)
530+
531+
self.course.start = tomorrow
532+
self.test_course.start = tomorrow
533+
self.course = self.update_course(self.course, self.user.id)
534+
self.test_course = self.update_course(self.test_course, self.user.id)
535+
536+
self.login(self.global_staff_user)
537+
self.enroll(self.course, True)
538+
self.enroll(self.test_course, True)
539+
540+
# and now should be able to load both
541+
self._check_staff_legacy_dark_launch(self.course)
542+
self._check_staff_legacy_dark_launch(self.test_course)
543+
358544

359545
class TestBetatesterAccess(ModuleStoreTestCase, CourseAccessTestMixin):
360546
"""

0 commit comments

Comments
 (0)