Commit 362240ff by chrisndodge

Merge pull request #42 from edx/cdodge/ignore-content-type

For the exam review callback, we can also get a callback that does no…
parents 449fcc1f 5580c995
...@@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse ...@@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.negotiation import BaseContentNegotiation
from edx_proctoring.api import ( from edx_proctoring.api import (
get_exam_attempt_by_code, get_exam_attempt_by_code,
...@@ -63,6 +64,27 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume ...@@ -63,6 +64,27 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume
) )
class IgnoreClientContentNegotiation(BaseContentNegotiation):
"""
This specialized class allows for more tolerance regarding
what the passed in Content-Type is. This is taken directly
from the Django REST Framework:
http://tomchristie.github.io/rest-framework-2-docs/api-guide/content-negotiation
"""
def select_parser(self, request, parsers):
"""
Select the first parser in the `.parser_classes` list.
"""
return parsers[0]
def select_renderer(self, request, renderers, format_suffix): # pylint: disable=signature-differs
"""
Select the first renderer in the `.renderer_classes` list.
"""
return (renderers[0], renderers[0].media_type)
class ExamReviewCallback(APIView): class ExamReviewCallback(APIView):
""" """
This endpoint is called by a 3rd party proctoring review service when This endpoint is called by a 3rd party proctoring review service when
...@@ -72,6 +94,8 @@ class ExamReviewCallback(APIView): ...@@ -72,6 +94,8 @@ class ExamReviewCallback(APIView):
this endpoint this endpoint
""" """
content_negotiation_class = IgnoreClientContentNegotiation
def post(self, request): def post(self, request):
""" """
Post callback handler Post callback handler
......
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
All tests for the proctored_exams.py All tests for the proctored_exams.py
""" """
import json import json
import pytz
from mock import Mock
from httmock import HTTMock from httmock import HTTMock
from string import Template # pylint: disable=deprecated-module from string import Template # pylint: disable=deprecated-module
from datetime import datetime from datetime import datetime
from django.test.client import Client from django.test.client import Client
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
import pytz from django.contrib.auth.models import User
from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAttempt, ProctoredExamStudentAllowance from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAttempt, ProctoredExamStudentAllowance
from edx_proctoring.views import require_staff from edx_proctoring.views import require_staff
from edx_proctoring.api import ( from edx_proctoring.api import (
...@@ -16,12 +19,10 @@ from edx_proctoring.api import ( ...@@ -16,12 +19,10 @@ from edx_proctoring.api import (
create_exam_attempt, create_exam_attempt,
get_exam_attempt_by_id, get_exam_attempt_by_id,
) )
from django.contrib.auth.models import User
from .utils import ( from .utils import (
LoggedInTestCase LoggedInTestCase
) )
from mock import Mock
from edx_proctoring.urls import urlpatterns from edx_proctoring.urls import urlpatterns
from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD
...@@ -1007,7 +1008,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1007,7 +1008,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
def test_review_caseinsensitive(self): def test_review_caseinsensitive(self):
""" """
Simulates a callback from the proctoring service with the Simulates a callback from the proctoring service with the
review data review data when we have different casing on the
external_id property
""" """
exam_id = create_exam( exam_id = create_exam(
...@@ -1041,6 +1043,43 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1041,6 +1043,43 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_review_bad_contenttype(self):
"""
Simulates a callback from the proctoring service when the
Content-Type is malformed
"""
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='foo'
)
self.assertEqual(response.status_code, 200)
def test_review_mismatch(self): def test_review_mismatch(self):
""" """
Simulates a callback from the proctoring service with the Simulates a callback from the proctoring service with the
......
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