REVE-23: Test Course Team Roles

- Create tests for the two types of course team roles (i.e. ensure that both instructor and staff course roles have access to graded content and their access won't expire)

Remaining work:
- This change does not include all types of course staff users (ex. discussion moderators, beta testers, TAs)
This commit is contained in:
Bessie Steinberg
2018-11-13 16:44:53 -05:00
parent d8184dc1bb
commit 1de077725a
2 changed files with 96 additions and 11 deletions

View File

@@ -15,7 +15,14 @@ from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.core.lib.url_utils import quote_slashes
from openedx.features.content_type_gating.partitions import CONTENT_GATING_PARTITION_ID
from openedx.features.course_duration_limits.config import CONTENT_TYPE_GATING_FLAG
from student.tests.factories import TEST_PASSWORD, AdminFactory, CourseEnrollmentFactory, UserFactory
from student.roles import CourseInstructorRole, CourseStaffRole
from student.tests.factories import (
AdminFactory,
CourseAccessRoleFactory,
CourseEnrollmentFactory,
UserFactory,
TEST_PASSWORD
)
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@@ -240,8 +247,9 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
Arguments:
block: some sort of xblock descriptor, must implement .scope_ids.usage_id
is_gated (bool): if True, this user is expected to be gated from this block
user_id (int): id of user, if not set will be set to self.audit_user.id
course_id (CourseLocator): id of course, if not set will be set to self.course.id
user_id (int): id of user
course_id (CourseLocator): id of course
view_name (str): type of view for the block, if not set will default to 'student_view'
"""
fake_request = self.factory.get('')
mock_get_current_request.return_value = fake_request
@@ -254,7 +262,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
usage_key_string=unicode(self.blocks_dict['vertical'].scope_ids.usage_id),
course=None
)
runtime = vertical_xblock.runtime
# This method of fetching the block from the descriptor bypassess access checks
@@ -368,3 +375,24 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
self.client.login(username=self.users[user].username, password=TEST_PASSWORD)
response = self.client.post(url)
self.assertEqual(response.status_code, status_code)
def test_access_course_team_users(self):
"""
Test that members of the course team do not lose access to graded content
"""
# There are two types of course team members: instructor and staff
# they have different privileges, but for the purpose of this test the important thing is that they should both
# have access to all graded content
instructor = UserFactory.create()
CourseInstructorRole(self.course.id).add_users(instructor)
staff = UserFactory.create()
CourseStaffRole(self.course.id).add_users(staff)
# assert that all course team members have access to graded content
for course_team_member in [instructor, staff]:
self._assert_block_is_gated(
block=self.blocks_dict['problem'],
user_id=course_team_member.id,
course_id=self.course.id,
is_gated=False
)

View File

@@ -16,6 +16,7 @@ from waffle.models import Flag
from waffle.testutils import override_flag
from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory
from courseware.tests.factories import StaffFactory
from courseware.tests.helpers import get_expiration_banner_text
from lms.djangoapps.commerce.models import CommerceConfiguration
@@ -31,6 +32,7 @@ from openedx.features.course_experience import (
UNIFIED_COURSE_TAB_FLAG
)
from student.models import CourseEnrollment
from student.roles import CourseInstructorRole, CourseStaffRole
from student.tests.factories import UserFactory
from util.date_utils import strftime_localized
from xmodule.modulestore import ModuleStoreEnum
@@ -54,6 +56,7 @@ TEST_COURSE_GOAL_OPTIONS = 'goal-options-container'
TEST_COURSE_GOAL_UPDATE_FIELD = 'section-goals'
TEST_COURSE_GOAL_UPDATE_FIELD_HIDDEN = 'section-goals hidden'
COURSE_GOAL_DISMISS_OPTION = 'unsure'
THREE_YEARS_AGO = now() - timedelta(days=(365 * 3))
QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES
@@ -94,7 +97,7 @@ class CourseHomePageTestCase(SharedModuleStoreTestCase):
Set up a course to be used for testing.
"""
# pylint: disable=super-method-not-called
with super(CourseHomePageTestCase, cls).setUpClassAndTestData():
with cls.setUpClassAndTestData():
with cls.store.default_store(ModuleStoreEnum.Type.split):
cls.course = CourseFactory.create(
org='edX',
@@ -116,6 +119,7 @@ class CourseHomePageTestCase(SharedModuleStoreTestCase):
@classmethod
def setUpTestData(cls):
"""Set up and enroll our fake user in the course."""
super(CourseHomePageTestCase, cls).setUpTestData()
cls.staff_user = StaffFactory(course_key=cls.course.id, password=TEST_PASSWORD)
cls.user = UserFactory(password=TEST_PASSWORD)
CourseEnrollment.enroll(cls.user, cls.course.id)
@@ -323,20 +327,70 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
)
self.assertRedirects(response, expected_url)
@override_waffle_flag(CONTENT_TYPE_GATING_FLAG, True)
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
def test_course_does_not_expire_for_different_roles(self):
"""
There are a number of different roles/users that should not lose access after the expiration date.
Ensure that users who should not lose access get a 200 (ok) response
when attempting to visit the course after their would be expiration date.
"""
course = CourseFactory.create(start=THREE_YEARS_AGO)
url = course_home_url(course)
# create a list of those users who should not lose their access,
# then assert that their access persists past the 'expiration date'
users_no_expired_access = []
verified_user = UserFactory(password=self.TEST_PASSWORD)
verified_enrollment = CourseEnrollment.enroll(verified_user, course.id, mode=CourseMode.VERIFIED)
ScheduleFactory(start=THREE_YEARS_AGO, enrollment=verified_enrollment)
users_no_expired_access.append((verified_user, 'Verified Learner'))
# There are two types of course team members: instructor and staff
# they have different privileges, but for the purpose of this test the important thing is that they should
# retain their access to the course after the access would expire for a normal audit learner
instructor = UserFactory.create(password=self.TEST_PASSWORD)
enrollment = CourseEnrollment.enroll(instructor, course.id, mode=CourseMode.AUDIT)
CourseInstructorRole(course.id).add_users(instructor)
ScheduleFactory(start=THREE_YEARS_AGO, enrollment=enrollment)
users_no_expired_access.append((instructor, 'Course Instructor'))
staff = UserFactory.create(password=self.TEST_PASSWORD)
enrollment = CourseEnrollment.enroll(staff, course.id, mode=CourseMode.AUDIT)
CourseStaffRole(course.id).add_users(staff)
ScheduleFactory(start=THREE_YEARS_AGO, enrollment=enrollment)
users_no_expired_access.append((staff, 'Course Staff'))
for user, user_description in users_no_expired_access:
self.client.login(username=user.username, password=self.TEST_PASSWORD)
response = self.client.get(url)
self.assertEqual(
response.status_code,
200,
"Should not expire access for user [{}]".format(user_description)
)
@override_waffle_flag(CONTENT_TYPE_GATING_FLAG, True)
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
def test_expired_course(self):
"""
Ensure that a user accessing an expired course sees a redirect to
the student dashboard, not a 404.
"""
three_years_ago = now() - timedelta(days=(365 * 3))
course = CourseFactory.create(start=three_years_ago)
user = self.create_user_for_course(course, CourseUserType.ENROLLED)
enrollment = CourseEnrollment.get_enrollment(user, course.id)
ScheduleFactory(start=three_years_ago, enrollment=enrollment)
"""
course = CourseFactory.create(start=THREE_YEARS_AGO)
url = course_home_url(course)
for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]:
CourseModeFactory.create(course_id=course.id, mode_slug=mode)
# assert that an if an expired audit user tries to access the course they are redirected to the dashboard
audit_user = UserFactory(password=self.TEST_PASSWORD)
self.client.login(username=audit_user.username, password=self.TEST_PASSWORD)
audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT)
ScheduleFactory(start=THREE_YEARS_AGO, enrollment=audit_enrollment)
response = self.client.get(url)
expiration_date = strftime_localized(course.start + timedelta(weeks=4), 'SHORT_DATE')
@@ -525,6 +579,9 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
class CourseHomeFragmentViewTests(ModuleStoreTestCase):
"""
Test Messages Displayed on the Course Home
"""
CREATE_USER = False
def setUp(self):