Add a test for Django-based file uploads to problems.
This commit is contained in:
@@ -314,24 +314,43 @@ class CodeResponseXMLFactory(ResponseXMLFactory):
|
|||||||
return super(CodeResponseXMLFactory, self).build_xml(**kwargs)
|
return super(CodeResponseXMLFactory, self).build_xml(**kwargs)
|
||||||
|
|
||||||
def create_response_element(self, **kwargs):
|
def create_response_element(self, **kwargs):
|
||||||
""" Create a <coderesponse> XML element:
|
"""
|
||||||
|
Create a <coderesponse> XML element.
|
||||||
|
|
||||||
Uses **kwargs:
|
Uses **kwargs:
|
||||||
|
|
||||||
|
*initial_display*: The code that initially appears in the textbox
|
||||||
|
[DEFAULT: "Enter code here"]
|
||||||
|
*answer_display*: The answer to display to the student
|
||||||
|
[DEFAULT: "This is the correct answer!"]
|
||||||
|
*grader_payload*: A JSON-encoded string sent to the grader
|
||||||
|
[DEFAULT: empty dict string]
|
||||||
|
*allowed_files*: A space-separated string of file names.
|
||||||
|
[DEFAULT: None]
|
||||||
|
*required_files*: A space-separated string of file names.
|
||||||
|
[DEFAULT: None]
|
||||||
|
|
||||||
*initial_display*: The code that initially appears in the textbox
|
|
||||||
[DEFAULT: "Enter code here"]
|
|
||||||
*answer_display*: The answer to display to the student
|
|
||||||
[DEFAULT: "This is the correct answer!"]
|
|
||||||
*grader_payload*: A JSON-encoded string sent to the grader
|
|
||||||
[DEFAULT: empty dict string]
|
|
||||||
"""
|
"""
|
||||||
# Get **kwargs
|
# Get **kwargs
|
||||||
initial_display = kwargs.get("initial_display", "Enter code here")
|
initial_display = kwargs.get("initial_display", "Enter code here")
|
||||||
answer_display = kwargs.get("answer_display", "This is the correct answer!")
|
answer_display = kwargs.get("answer_display", "This is the correct answer!")
|
||||||
grader_payload = kwargs.get("grader_payload", '{}')
|
grader_payload = kwargs.get("grader_payload", '{}')
|
||||||
|
allowed_files = kwargs.get("allowed_files", None)
|
||||||
|
required_files = kwargs.get("required_files", None)
|
||||||
|
|
||||||
# Create the <coderesponse> element
|
# Create the <coderesponse> element
|
||||||
response_element = etree.Element("coderesponse")
|
response_element = etree.Element("coderesponse")
|
||||||
|
|
||||||
|
# If files are involved, create the <filesubmission> element.
|
||||||
|
has_files = allowed_files or required_files
|
||||||
|
if has_files:
|
||||||
|
filesubmission_element = etree.SubElement(response_element, "filesubmission")
|
||||||
|
if allowed_files:
|
||||||
|
filesubmission_element.set("allowed_files", allowed_files)
|
||||||
|
if required_files:
|
||||||
|
filesubmission_element.set("required_files", required_files)
|
||||||
|
|
||||||
|
# Create the <codeparam> element.
|
||||||
codeparam_element = etree.SubElement(response_element, "codeparam")
|
codeparam_element = etree.SubElement(response_element, "codeparam")
|
||||||
|
|
||||||
# Set the initial display text
|
# Set the initial display text
|
||||||
@@ -347,8 +366,9 @@ class CodeResponseXMLFactory(ResponseXMLFactory):
|
|||||||
grader_element.text = str(grader_payload)
|
grader_element.text = str(grader_payload)
|
||||||
|
|
||||||
# Create the input within the response
|
# Create the input within the response
|
||||||
input_element = etree.SubElement(response_element, "textbox")
|
if not has_files:
|
||||||
input_element.set("mode", "python")
|
input_element = etree.SubElement(response_element, "textbox")
|
||||||
|
input_element.set("mode", "python")
|
||||||
|
|
||||||
return response_element
|
return response_element
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
|
|
||||||
# text processing dependancies
|
# text processing dependancies
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
@@ -18,7 +22,10 @@ from xmodule.modulestore.django import modulestore, editable_modulestore
|
|||||||
#import factories and parent testcase modules
|
#import factories and parent testcase modules
|
||||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||||
from capa.tests.response_xml_factory import OptionResponseXMLFactory, CustomResponseXMLFactory, SchematicResponseXMLFactory
|
from capa.tests.response_xml_factory import (
|
||||||
|
OptionResponseXMLFactory, CustomResponseXMLFactory, SchematicResponseXMLFactory,
|
||||||
|
CodeResponseXMLFactory,
|
||||||
|
)
|
||||||
from courseware.tests.helpers import LoginEnrollmentTestCase
|
from courseware.tests.helpers import LoginEnrollmentTestCase
|
||||||
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
|
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
|
||||||
from lms.lib.xblock.runtime import quote_slashes
|
from lms.lib.xblock.runtime import quote_slashes
|
||||||
@@ -547,6 +554,58 @@ class TestCourseGrader(TestSubmittingProblems):
|
|||||||
self.assertEqual(self.score_for_hw('homework3'), [1.0, 1.0])
|
self.assertEqual(self.score_for_hw('homework3'), [1.0, 1.0])
|
||||||
|
|
||||||
|
|
||||||
|
class ProblemWithUploadedFilesTest(TestSubmittingProblems):
|
||||||
|
"""Tests of problems with uploaded files."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ProblemWithUploadedFilesTest, self).setUp()
|
||||||
|
self.section = self.add_graded_section_to_course('section')
|
||||||
|
|
||||||
|
def problem_setup(self, name, files):
|
||||||
|
"""
|
||||||
|
Create a CodeResponse problem with files to upload.
|
||||||
|
"""
|
||||||
|
|
||||||
|
xmldata = CodeResponseXMLFactory().build_xml(
|
||||||
|
allowed_files=files, required_files=files,
|
||||||
|
)
|
||||||
|
ItemFactory.create(
|
||||||
|
parent_location=self.section.location,
|
||||||
|
category='problem',
|
||||||
|
display_name=name,
|
||||||
|
data=xmldata
|
||||||
|
)
|
||||||
|
|
||||||
|
# re-fetch the course from the database so the object is up to date
|
||||||
|
self.refresh_course()
|
||||||
|
|
||||||
|
def test_three_files(self):
|
||||||
|
# Open the test files, and arrange to close them later.
|
||||||
|
filenames = "prog1.py prog2.py prog3.py"
|
||||||
|
fileobjs = [
|
||||||
|
open(os.path.join(settings.COMMON_TEST_DATA_ROOT, "capa", filename))
|
||||||
|
for filename in filenames.split()
|
||||||
|
]
|
||||||
|
for fileobj in fileobjs:
|
||||||
|
self.addCleanup(fileobj.close)
|
||||||
|
|
||||||
|
self.problem_setup("the_problem", filenames)
|
||||||
|
with patch('courseware.module_render.xqueue_interface.session') as mock_session:
|
||||||
|
resp = self.submit_question_answer("the_problem", {'2_1': fileobjs})
|
||||||
|
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
self.assertEqual(json_resp['success'], "incorrect")
|
||||||
|
|
||||||
|
# See how post got called.
|
||||||
|
name, args, kwargs = mock_session.mock_calls[0]
|
||||||
|
self.assertEqual(name, "post")
|
||||||
|
self.assertEqual(len(args), 1)
|
||||||
|
self.assertTrue(args[0].endswith("/submit/"))
|
||||||
|
self.assertItemsEqual(kwargs.keys(), ["files", "data"])
|
||||||
|
self.assertItemsEqual(kwargs['files'].keys(), filenames.split())
|
||||||
|
|
||||||
|
|
||||||
class TestPythonGradedResponse(TestSubmittingProblems):
|
class TestPythonGradedResponse(TestSubmittingProblems):
|
||||||
"""
|
"""
|
||||||
Check that we can submit a schematic and custom response, and it answers properly.
|
Check that we can submit a schematic and custom response, and it answers properly.
|
||||||
|
|||||||
Reference in New Issue
Block a user