fix: fixed atmoic block error in course_status_info

* fix: fixed atmoic block error in course_status_info

We are getting "An error occurred in the current transaction. You cant execute queries until the end of the atomic block."
error in get course status info on both versions i.e. 0.5 and 1. I was unable to reproduce it locally. But by looking
in django documentation and some other online helps I concluded that it might be because of some db intefrity error
that we didnt handle properly and now the cursor is broken for this transaction. Therefore i am making it non atomic
transaction. Since its a get request we can make transactions run independentantly.

LEARNER-8267
This commit is contained in:
jawad khan
2021-06-17 07:26:11 +05:00
committed by GitHub
parent 2b445f13be
commit ad2f92767b
2 changed files with 63 additions and 2 deletions

View File

@@ -11,15 +11,17 @@ import ddt
import pytz
from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing
from django.conf import settings
from django.db import transaction
from django.template import defaultfilters
from django.test import RequestFactory, override_settings
from django.utils import timezone
from django.utils.timezone import now
from milestones.tests.utils import MilestonesTestCaseMixin
from opaque_keys.edx.keys import CourseKey
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.util.milestones_helpers import set_prerequisite_courses
from common.djangoapps.util.testing import UrlResetMixin
from lms.djangoapps.certificates.data import CertificateStatuses
@@ -439,6 +441,7 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
"""
Tests for GET of /api/mobile/v<version_number>/users/<user_name>/course_status_info/{course_id}
"""
def test_success_v0(self):
self.login_and_enroll()
@@ -454,6 +457,53 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
response = self.api_response(api_version=API_V1)
assert response.data['last_visited_block_id'] == str(self.unit.location)
# Since we are testing an non atomic view in atomic test case, therefore we are expecting error on failures
def api_error_response(self, reverse_args=None, data=None, **kwargs):
"""
Same as api response from MobileAPITestCase but handle views which throw errors
"""
url = self.reverse_url(reverse_args, **kwargs)
try:
with transaction.atomic():
self.url_method(url, data=data, **kwargs)
assert False
except transaction.TransactionManagementError:
assert True
def test_invalid_user(self):
self.login_and_enroll()
self.api_error_response(username='no_user')
def test_other_user(self):
# login and enroll as the test user
self.login_and_enroll()
self.logout()
# login and enroll as another user
other = UserFactory.create()
self.client.login(username=other.username, password='test')
self.enroll()
self.logout()
# now login and call the API as the test user
self.login()
self.api_error_response(username=other.username)
def test_course_not_found(self):
non_existent_course_id = CourseKey.from_string('a/b/c')
self.init_course_access(course_id=non_existent_course_id)
self.api_error_response(course_id=non_existent_course_id)
def test_unenrolled_user(self):
self.login()
self.unenroll()
self.api_error_response(expected_response_code=None)
def test_no_auth(self):
self.logout()
self.api_error_response()
class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
MobileCourseAccessTestMixin, MilestonesTestCaseMixin):

View File

@@ -7,12 +7,15 @@ from completion.exceptions import UnavailableCompletionData
from completion.utilities import get_key_to_last_completed_block
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.contrib.auth.signals import user_logged_in
from django.db import transaction
from django.shortcuts import redirect
from django.utils import dateparse
from django.utils.decorators import method_decorator
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import UsageKey
from rest_framework import generics, views
from rest_framework.decorators import api_view
from rest_framework.permissions import SAFE_METHODS
from rest_framework.response import Response
from xblock.fields import Scope
from xblock.runtime import KeyValueStore
@@ -77,6 +80,7 @@ class UserDetail(generics.RetrieveAPIView):
@mobile_view(is_user=True)
@method_decorator(transaction.non_atomic_requests, name='dispatch')
class UserCourseStatus(views.APIView):
"""
**Use Cases**
@@ -122,6 +126,13 @@ class UserCourseStatus(views.APIView):
http_method_names = ["get", "patch"]
def dispatch(self, request, *args, **kwargs):
if request.method in SAFE_METHODS:
return super().dispatch(request, *args, **kwargs)
else:
with transaction.atomic():
return super().dispatch(request, *args, **kwargs)
def _last_visited_module_path(self, request, course):
"""
Returns the path from the last module visited by the current user in the given course up to
@@ -135,7 +146,7 @@ class UserCourseStatus(views.APIView):
request.user, request, course, field_data_cache, course.id, course=course
)
path = [course_module]
path = [course_module] if course_module else []
chapter = get_current_child(course_module, min_depth=2)
if chapter is not None:
path.append(chapter)