From 45d8086e1cd5ac4fb7a583a411a9b7bdda27491b Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Fri, 15 Mar 2013 11:40:22 -0400 Subject: [PATCH] Set up ajax to submit to XQueue. Add some unit tests to make sure this is working properly --- common/lib/capa/capa/inputtypes.py | 37 +++++++++-- common/lib/capa/capa/responsetypes.py | 5 +- common/lib/capa/capa/tests/__init__.py | 9 ++- common/lib/capa/capa/tests/test_inputtypes.py | 63 +++++++++++++++++++ 4 files changed, 105 insertions(+), 9 deletions(-) diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index f49ad5b422..08c395692f 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -48,6 +48,8 @@ import pyparsing from .registry import TagRegistry from capa.chem import chemcalc +import xqueue_interface +from datetime import datetime log = logging.getLogger(__name__) @@ -639,6 +641,7 @@ class MatlabInput(CodeInput): # Check if problem has been queued self.queue_len = 0 + self.queuename = 'matlab' # Flag indicating that the problem has been queued, 'msg' is length of # queue if self.status == 'incomplete': @@ -650,20 +653,44 @@ class MatlabInput(CodeInput): def handle_ajax(self, dispatch, get): if dispatch == 'plot': - # put the data in the queue and ship it off - pass - elif dispatch == 'display': + return self.plot_data(get) + elif dispatch == 'xqueue_response': # render the response pass def plot_data(self, get): ''' send data via xqueue to the mathworks backend''' - # only send data if xqueue exists if self.system.xqueue is not None: - pass + # pull relevant info out of get + response = get['submission'] + + # construct xqueue headers + qinterface = self.system.xqueue['interface'] + qtime = datetime.strftime(datetime.now(), xqueue_interface.dateformat) + callback_url = self.system.xqueue['construct_callback']('input_ajax') + anonymous_student_id = self.system.anonymous_student_id + queuekey = xqueue_interface.make_hashkey(str(self.system.seed) + qtime + + anonymous_student_id + + self.id) + xheader = xqueue_interface.make_xheader( + lms_callback_url = callback_url, + lms_key = queuekey, + queue_name = self.queuename) + # construct xqueue body + student_info = {'anonymous_student_id': anonymous_student_id, + 'submission_time': qtime} + contents = {'grader_payload': self.plot_payload, + 'student_info': json.dumps(student_info), + 'student_response': response} + + (error, msg) = qinterface.send_to_queue(header=xheader, + body = json.dumps(contents)) + + return json.dumps({'success': error != 0, 'message': msg}) + return json.dumps({'success': False, 'message': 'Cannot connect to the queue'}) registry.register(MatlabInput) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index f997829cd0..bb202e6d6e 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1271,8 +1271,9 @@ class CodeResponse(LoncapaResponse): Expects 'xqueue' dict in ModuleSystem with the following keys that are needed by CodeResponse: system.xqueue = { 'interface': XqueueInterface object, - 'callback_url': Per-StudentModule callback URL - where results are posted (string), + 'construct_callback': Per-StudentModule callback URL + constructor, defaults to using 'score_update' + as the correct dispatch (function), 'default_queuename': Default queuename to submit request (string) } diff --git a/common/lib/capa/capa/tests/__init__.py b/common/lib/capa/capa/tests/__init__.py index 89cb5a5ee9..7b1bffce62 100644 --- a/common/lib/capa/capa/tests/__init__.py +++ b/common/lib/capa/capa/tests/__init__.py @@ -2,7 +2,7 @@ import fs import fs.osfs import os -from mock import Mock +from mock import Mock, MagicMock import xml.sax.saxutils as saxutils @@ -16,6 +16,11 @@ def tst_render_template(template, context): """ return '
{0}
'.format(saxutils.escape(repr(context))) +def calledback_url(dispatch = 'score_update'): + return dispatch + +xqueue_interface = MagicMock() +xqueue_interface.send_to_queue.return_value = (1, 'Success!') test_system = Mock( ajax_url='courses/course_id/modx/a_location', @@ -26,7 +31,7 @@ test_system = Mock( user=Mock(), filestore=fs.osfs.OSFS(os.path.join(TEST_DIR, "test_files")), debug=True, - xqueue={'interface': None, 'callback_url': '/', 'default_queuename': 'testqueue', 'waittime': 10}, + xqueue={'interface': xqueue_interface, 'construct_callback': calledback_url, 'default_queuename': 'testqueue', 'waittime': 10}, node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"), anonymous_student_id='student' ) diff --git a/common/lib/capa/capa/tests/test_inputtypes.py b/common/lib/capa/capa/tests/test_inputtypes.py index 360fd9f2f6..01801ac822 100644 --- a/common/lib/capa/capa/tests/test_inputtypes.py +++ b/common/lib/capa/capa/tests/test_inputtypes.py @@ -23,6 +23,7 @@ import xml.sax.saxutils as saxutils from . import test_system from capa import inputtypes +from mock import ANY # just a handy shortcut lookup_tag = inputtypes.registry.get_class_for_tag @@ -300,6 +301,68 @@ class CodeInputTest(unittest.TestCase): self.assertEqual(context, expected) +class MatlabTest(unittest.TestCase): + ''' + Test Matlab input types + ''' + def setUp(self): + self.rows = '10' + self.cols = '80' + self.tabsize = '4' + self.mode = "" + self.payload = "payload" + self.linenumbers = 'true' + self.xml = """ + + {payload} + + """.format(r = self.rows, + c = self.cols, + tabsize = self.tabsize, + m = self.mode, + payload = self.payload, + ln = self.linenumbers) + elt = etree.fromstring(self.xml) + state = {'value': 'print "good evening"', + 'status': 'incomplete', + 'feedback': {'message': '3'}, } + + self.input_class = lookup_tag('matlabinput') + self.the_input = self.input_class(test_system, elt, state) + + + def test_rendering(self): + context = self.the_input._get_render_context() + + expected = {'id': 'prob_1_2', + 'value': 'print "good evening"', + 'status': 'queued', + 'msg': self.input_class.submitted_msg, + 'mode': self.mode, + 'rows': self.rows, + 'cols': self.cols, + 'linenumbers': 'true', + 'hidden': '', + 'tabsize': int(self.tabsize), + 'queue_len': '3', + } + + self.assertEqual(context, expected) + + def test_plot_data(self): + get = {'submission': 'x = 1234;'} + response = json.loads(self.the_input.handle_ajax("plot", get)) + + test_system.xqueue['interface'].send_to_queue.assert_called_with(header=ANY, body=ANY) + + + self.assertTrue(response['success']) + + + class SchematicTest(unittest.TestCase): '''