Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions openedx/features/course_experience/api/v1/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""
Tests utils of course expirience feature.
"""
import datetime

from django.urls import reverse
from django.utils import timezone
from rest_framework.test import APIRequestFactory

from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.util.testing import EventTestMixin
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin
from openedx.core.djangoapps.schedules.models import Schedule
from openedx.features.course_experience.api.v1.utils import (
reset_deadlines_for_course,
reset_course_deadlines_for_user,
reset_bulk_course_deadlines
)
from xmodule.modulestore.tests.factories import CourseFactory


class TestResetDeadlinesForCourse(EventTestMixin, BaseCourseHomeTests, MasqueradeMixin):
"""
Tests for reset deadlines endpoint.
"""
def setUp(self): # pylint: disable=arguments-differ
super().setUp("openedx.features.course_experience.api.v1.utils.tracker")
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))

def test_reset_deadlines_for_course(self):
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
enrollment.schedule.save()

request = APIRequestFactory().post(
reverse("course-experience-reset-course-deadlines"), {"course_key": self.course.id}
)
request.user = self.user

reset_deadlines_for_course(request, self.course.id, {})

assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
self.assert_event_emitted(
"edx.ui.lms.reset_deadlines.clicked",
courserun_key=str(self.course.id),
is_masquerading=False,
is_staff=False,
org_key=self.course.org,
user_id=self.user.id,
)

def test_reset_deadlines_with_masquerade(self):
"""Staff users should be able to masquerade as a learner and reset the learner's schedule"""
student_username = self.user.username
student_user_id = self.user.id
student_enrollment = CourseEnrollment.enroll(self.user, self.course.id)
student_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
student_enrollment.schedule.save()

staff_enrollment = CourseEnrollment.enroll(self.staff_user, self.course.id)
staff_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=30)
staff_enrollment.schedule.save()

self.switch_to_staff()
self.update_masquerade(course=self.course, username=student_username)

request = APIRequestFactory().post(
reverse("course-experience-reset-course-deadlines"), {"course_key": self.course.id}
)
request.user = self.staff_user
request.session = self.client.session

reset_deadlines_for_course(request, self.course.id, {})

updated_schedule = Schedule.objects.get(id=student_enrollment.schedule.id)
assert updated_schedule.start_date.date() == datetime.datetime.today().date()
updated_staff_schedule = Schedule.objects.get(id=staff_enrollment.schedule.id)
assert updated_staff_schedule.start_date == staff_enrollment.schedule.start_date
self.assert_event_emitted(
"edx.ui.lms.reset_deadlines.clicked",
courserun_key=str(self.course.id),
is_masquerading=True,
is_staff=False,
org_key=self.course.org,
user_id=student_user_id,
)

def test_reset_course_deadlines_for_user(self):
"""Test the reset_course_deadlines_for_user utility function directly"""
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
enrollment.schedule.save()

result = reset_course_deadlines_for_user(self.user, self.course.id)

assert result is True
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date

def test_reset_bulk_course_deadlines(self):
"""Test the reset_bulk_course_deadlines utility function"""
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
enrollment.schedule.save()

request = APIRequestFactory().post(
reverse("course-experience-reset-all-course-deadlines"), {}
)
request.user = self.user

success_keys, failed_keys = reset_bulk_course_deadlines(request, [self.course.id], {})

assert len(success_keys) == 1
assert self.course.id in success_keys
assert len(failed_keys) == 0
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
97 changes: 53 additions & 44 deletions openedx/features/course_experience/api/v1/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""
Tests for reset deadlines endpoint.
"""

import datetime
from unittest import mock

import ddt
from django.urls import reverse
Expand All @@ -10,7 +12,6 @@

from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.util.testing import EventTestMixin
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin
from openedx.core.djangoapps.schedules.models import Schedule
Expand All @@ -19,14 +20,12 @@


@ddt.ddt
class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, MasqueradeMixin):
class ResetCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
"""
Tests for reset deadlines endpoint.
"""
def setUp(self): # pylint: disable=arguments-differ
# Need to supply tracker name for the EventTestMixin. Also, EventTestMixin needs to come
# first in class inheritance so the setUp call here appropriately works
super().setUp('openedx.features.course_experience.api.v1.views.tracker')
super().setUp()
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))

def test_reset_deadlines(self):
Expand All @@ -37,20 +36,11 @@ def test_reset_deadlines(self):
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course': self.course.id})
assert response.status_code == 400
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
self.assert_no_events_were_emitted()

# Test correct post body
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
assert response.status_code == 200
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
self.assert_event_emitted(
'edx.ui.lms.reset_deadlines.clicked',
courserun_key=str(self.course.id),
is_masquerading=False,
is_staff=False,
org_key=self.course.org,
user_id=self.user.id,
)

@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
@override_waffle_flag(RELATIVE_DATES_DISABLE_RESET_FLAG, active=True)
Expand All @@ -62,36 +52,6 @@ def test_reset_deadlines_disabled(self):
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
assert response.status_code == 200
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
self.assert_no_events_were_emitted()

def test_reset_deadlines_with_masquerade(self):
""" Staff users should be able to masquerade as a learner and reset the learner's schedule """
student_username = self.user.username
student_user_id = self.user.id
student_enrollment = CourseEnrollment.enroll(self.user, self.course.id)
student_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
student_enrollment.schedule.save()

staff_enrollment = CourseEnrollment.enroll(self.staff_user, self.course.id)
staff_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=30)
staff_enrollment.schedule.save()

self.switch_to_staff()
self.update_masquerade(course=self.course, username=student_username)

self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
updated_schedule = Schedule.objects.get(id=student_enrollment.schedule.id)
assert updated_schedule.start_date.date() == datetime.datetime.today().date()
updated_staff_schedule = Schedule.objects.get(id=staff_enrollment.schedule.id)
assert updated_staff_schedule.start_date == staff_enrollment.schedule.start_date
self.assert_event_emitted(
'edx.ui.lms.reset_deadlines.clicked',
courserun_key=str(self.course.id),
is_masquerading=True,
is_staff=False,
org_key=self.course.org,
user_id=student_user_id,
)

def test_post_unauthenticated_user(self):
self.client.logout()
Expand All @@ -115,3 +75,52 @@ def test_mobile_get_unauthenticated_user(self):
self.client.logout()
response = self.client.get(reverse('course-experience-course-deadlines-mobile', args=[self.course.id]))
assert response.status_code == 401


class ResetAllRelativeCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
"""
Tests for reset all relative deadlines endpoint.
"""

def setUp(self): # pylint: disable=arguments-differ
super().setUp()
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))
self.enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
self.enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
self.enrollment.schedule.save()

def test_reset_all_course_deadlines(self):
"""
Test reset all course deadlines endpoint
"""
response = self.client.post(
reverse("course-experience-reset-all-course-deadlines"),
{},
)
assert response.status_code == 200
assert self.enrollment.schedule.start_date < Schedule.objects.get(id=self.enrollment.schedule.id).start_date
assert str(self.course.id) in response.data.get("success_course_keys")

def test_reset_all_course_deadlines_failure(self):
"""
Raise exception on reset_bulk_course_deadlines and assert if failure course id is returned
"""
with mock.patch(
"openedx.features.course_experience.api.v1.views.reset_bulk_course_deadlines",
return_value=([], [self.course.id]),
):
response = self.client.post(reverse("course-experience-reset-all-course-deadlines"), {})

assert response.status_code == 200
assert str(self.course.id) in response.data.get("failed_course_keys")

def test_post_unauthenticated_user(self):
"""
Test reset all relative course deadlines endpoint for unauthenticated user
"""
self.client.logout()
response = self.client.post(
reverse("course-experience-reset-all-course-deadlines"),
{},
)
assert response.status_code == 401
13 changes: 11 additions & 2 deletions openedx/features/course_experience/api/v1/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@


from django.conf import settings
from django.urls import re_path
from django.urls import re_path, path

from openedx.features.course_experience.api.v1.views import reset_course_deadlines, CourseDeadlinesMobileView
from openedx.features.course_experience.api.v1.views import (
reset_course_deadlines,
reset_all_course_deadlines,
CourseDeadlinesMobileView,
)

urlpatterns = []

Expand All @@ -17,6 +21,11 @@
reset_course_deadlines,
name='course-experience-reset-course-deadlines'
),
path(
'v1/reset_all_course_deadlines/',
reset_all_course_deadlines,
name='course-experience-reset-all-course-deadlines',
)
]

# URL for retrieving course deadlines info
Expand Down
Loading
Loading