Commit 2cfccdf6 by Chris Dodge

treat the ssiExamLocator as potentially case insensitive, since I've seen…

treat the ssiExamLocator as potentially case insensitive, since I've seen different casing used in different user-cases
parent 76e8bd48
...@@ -152,7 +152,10 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -152,7 +152,10 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
raise StudentExamAttemptDoesNotExistsException(err_msg) raise StudentExamAttemptDoesNotExistsException(err_msg)
# then make sure we have the right external_id # then make sure we have the right external_id
if attempt_obj.external_id != external_id: # note that SoftwareSecure might send a case insensitive
# ssiRecordLocator than what it returned when we registered the
# exam
if attempt_obj.external_id.lower() != external_id.lower():
err_msg = ( err_msg = (
'Found attempt_code {attempt_code}, but the recorded external_id did not ' 'Found attempt_code {attempt_code}, but the recorded external_id did not '
'match the ssiRecordLocator that had been recorded previously. Has {existing} ' 'match the ssiRecordLocator that had been recorded previously. Has {existing} '
......
...@@ -18,6 +18,8 @@ from edx_proctoring.api import ( ...@@ -18,6 +18,8 @@ from edx_proctoring.api import (
mark_exam_attempt_as_ready, mark_exam_attempt_as_ready,
update_exam_attempt) update_exam_attempt)
from edx_proctoring.exceptions import ProctoredBaseException
from edx_proctoring.backends import get_backend_provider from edx_proctoring.backends import get_backend_provider
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -77,7 +79,15 @@ class ExamReviewCallback(APIView): ...@@ -77,7 +79,15 @@ class ExamReviewCallback(APIView):
provider = get_backend_provider() provider = get_backend_provider()
# call down into the underlying provider code # call down into the underlying provider code
provider.on_review_callback(request.DATA) try:
provider.on_review_callback(request.DATA)
except ProctoredBaseException, ex:
return Response(
data={
'reason': unicode(ex)
},
status=400
)
return Response( return Response(
data='OK', data='OK',
......
...@@ -1004,6 +1004,80 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1004,6 +1004,80 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_review_caseinsensitive(self):
"""
Simulates a callback from the proctoring service with the
review data
"""
exam_id = create_exam(
course_id='foo/bar/baz',
content_id='content',
exam_name='Sample Exam',
time_limit_mins=10,
is_proctored=True
)
# be sure to use the mocked out SoftwareSecure handlers
with HTTMock(mock_response_content):
attempt_id = create_exam_attempt(
exam_id,
self.user.id,
taking_as_proctored=True
)
attempt = get_exam_attempt_by_id(attempt_id)
self.assertIsNotNone(attempt['external_id'])
test_payload = Template(TEST_REVIEW_PAYLOAD).substitute(
attempt_code=attempt['attempt_code'],
external_id=attempt['external_id'].upper()
)
response = self.client.post(
reverse('edx_proctoring.anonymous.proctoring_review_callback'),
data=test_payload,
content_type='application/json'
)
self.assertEqual(response.status_code, 200)
def test_review_mismatch(self):
"""
Simulates a callback from the proctoring service with the
review data but the external_ids don't match
"""
exam_id = create_exam(
course_id='foo/bar/baz',
content_id='content',
exam_name='Sample Exam',
time_limit_mins=10,
is_proctored=True
)
# be sure to use the mocked out SoftwareSecure handlers
with HTTMock(mock_response_content):
attempt_id = create_exam_attempt(
exam_id,
self.user.id,
taking_as_proctored=True
)
attempt = get_exam_attempt_by_id(attempt_id)
self.assertIsNotNone(attempt['external_id'])
test_payload = Template(TEST_REVIEW_PAYLOAD).substitute(
attempt_code=attempt['attempt_code'],
external_id='mismatch'
)
response = self.client.post(
reverse('edx_proctoring.anonymous.proctoring_review_callback'),
data=test_payload,
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
def test_review_callback_get(self): def test_review_callback_get(self):
""" """
We don't support any http METHOD other than GET We don't support any http METHOD other than GET
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment