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
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.negotiation import BaseContentNegotiation
from edx_proctoring.api import (
get_exam_attempt_by_code,
......@@ -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):
"""
This endpoint is called by a 3rd party proctoring review service when
......@@ -72,6 +94,8 @@ class ExamReviewCallback(APIView):
this endpoint
"""
content_negotiation_class = IgnoreClientContentNegotiation
def post(self, request):
"""
Post callback handler
......
......@@ -3,12 +3,15 @@
All tests for the proctored_exams.py
"""
import json
import pytz
from mock import Mock
from httmock import HTTMock
from string import Template # pylint: disable=deprecated-module
from datetime import datetime
from django.test.client import Client
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.views import require_staff
from edx_proctoring.api import (
......@@ -16,12 +19,10 @@ from edx_proctoring.api import (
create_exam_attempt,
get_exam_attempt_by_id,
)
from django.contrib.auth.models import User
from .utils import (
LoggedInTestCase
)
from mock import Mock
from edx_proctoring.urls import urlpatterns
from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD
......@@ -1007,7 +1008,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
def test_review_caseinsensitive(self):
"""
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(
......@@ -1041,6 +1043,43 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
)
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):
"""
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