def test_open_ended_display(self):
        """
        Test storing answer with the open ended module.
        """

        # Create a module with no state yet.  Important that this start off as a blank slate.
        test_module = OpenEndedModule(self.test_system, self.location,
                                                self.definition, self.descriptor, self.static_data, self.metadata)

        saved_response = "Saved response."
        submitted_response = "Submitted response."

        # Initially, there will be no stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # And the initial answer to display will be an empty string.
        self.assertEqual(test_module.get_display_answer(), "")

        # Now, store an answer in the module.
        test_module.handle_ajax("store_answer", {'student_answer' : saved_response}, get_test_system())
        # The stored answer should now equal our response.
        self.assertEqual(test_module.stored_answer, saved_response)
        self.assertEqual(test_module.get_display_answer(), saved_response)

        # Mock out the send_to_grader function so it doesn't try to connect to the xqueue.
        test_module.send_to_grader = Mock(return_value=True)
        # Submit a student response to the question.
        test_module.handle_ajax(
            "save_answer",
            {"student_answer": submitted_response},
            get_test_system()
        )
        # Submitting an answer should clear the stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # Confirm that the answer is stored properly.
        self.assertEqual(test_module.latest_answer(), submitted_response)
    def setUp(self):
        self.test_system = get_test_system()

        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback,
                                   'default_queuename': 'testqueue',
                                   'waittime': 1}
        self.openendedmodule = OpenEndedModule(self.test_system, self.location,
                                               self.definition, self.descriptor, self.static_data, self.metadata)
Example #3
0
    def test_open_ended_display(self):
        """
        Test storing answer with the open ended module.
        """

        # Create a module with no state yet.  Important that this start off as a blank slate.
        test_module = OpenEndedModule(self.test_system, self.location,
                                      self.definition, self.descriptor,
                                      self.static_data, self.metadata)

        saved_response = "Saved response."
        submitted_response = "Submitted response."

        # Initially, there will be no stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # And the initial answer to display will be an empty string.
        self.assertEqual(test_module.get_display_answer(), "")

        # Now, store an answer in the module.
        test_module.handle_ajax("store_answer",
                                {'student_answer': saved_response},
                                get_test_system())
        # The stored answer should now equal our response.
        self.assertEqual(test_module.stored_answer, saved_response)
        self.assertEqual(test_module.get_display_answer(), saved_response)

        # Mock out the send_to_grader function so it doesn't try to connect to the xqueue.
        test_module.send_to_grader = Mock(return_value=True)
        # Submit a student response to the question.
        test_module.handle_ajax(
            "save_answer", {
                "student_answer": submitted_response,
                "can_upload_files": False,
                "student_file": None
            }, get_test_system())
        # Submitting an answer should clear the stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # Confirm that the answer is stored properly.
        self.assertEqual(test_module.latest_answer(), submitted_response)
    def setUp(self):
        self.test_system = get_test_system()
        self.test_system.open_ended_grading_interface = None
        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback,
                                   'default_queuename': 'testqueue',
                                   'waittime': 1}
        self.openendedmodule = OpenEndedModule(self.test_system, self.location,
                                               self.definition, self.descriptor, self.static_data, self.metadata)
class OpenEndedModuleTest(unittest.TestCase):
    """
    Test the open ended module class
    """
    location = Location(["i4x", "edX", "sa_test", "selfassessment",
                         "SampleQuestion"])

    metadata = json.dumps({'attempts': '10'})
    prompt = etree.XML("<prompt>This is a question prompt</prompt>")
    rubric = etree.XML('''<rubric>
        <category>
        <description>Response Quality</description>
        <option>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option>
        </category>
         </rubric>''')
    max_score = 4

    static_data = {
        'max_attempts': 20,
        'prompt': prompt,
        'rubric': rubric,
        'max_score': max_score,
        'display_name': 'Name',
        'accept_file_upload': False,
        'close_date': None,
        's3_interface': test_util_open_ended.S3_INTERFACE,
        'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
        'skip_basic_checks': False,
        'control': {
            'required_peer_grading': 1,
            'peer_grader_count': 1,
            'min_to_calibrate': 3,
            'max_to_calibrate': 6,
            'peer_grade_finished_submissions_when_none_pending': False,
        }
    }

    oeparam = etree.XML('''
      <openendedparam>
            <initial_display>Enter essay here.</initial_display>
            <answer_display>This is the answer.</answer_display>
            <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload>
        </openendedparam>
    ''')
    definition = {'oeparam': oeparam}
    descriptor = Mock()

    def setUp(self):
        self.test_system = get_test_system()
        self.test_system.open_ended_grading_interface = None
        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback,
                                   'default_queuename': 'testqueue',
                                   'waittime': 1}
        self.openendedmodule = OpenEndedModule(self.test_system, self.location,
                                               self.definition, self.descriptor, self.static_data, self.metadata)

    def test_message_post(self):
        get = {'feedback': 'feedback text',
               'submission_id': '1',
               'grader_id': '1',
               'score': 3}
        qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat)
        student_info = {'anonymous_student_id': self.test_system.anonymous_student_id,
                        'submission_time': qtime}
        contents = {
            'feedback': get['feedback'],
            'submission_id': int(get['submission_id']),
            'grader_id': int(get['grader_id']),
            'score': get['score'],
            'student_info': json.dumps(student_info)
        }

        result = self.openendedmodule.message_post(get, self.test_system)
        self.assertTrue(result['success'])
        # make sure it's actually sending something we want to the queue
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

        state = json.loads(self.openendedmodule.get_instance_state())
        self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE)

    def test_send_to_grader(self):
        submission = "This is a student submission"
        qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat)
        student_info = {'anonymous_student_id': self.test_system.anonymous_student_id,
                        'submission_time': qtime}
        contents = self.openendedmodule.payload.copy()
        contents.update({
            'student_info': json.dumps(student_info),
            'student_response': submission,
            'max_score': self.max_score
        })
        result = self.openendedmodule.send_to_grader(submission, self.test_system)
        self.assertTrue(result)
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        score_msg = {
            'correct': True,
            'score': 4,
            'msg': 'Grader Message',
            'feedback': "Grader Feedback"
        }
        get = {'queuekey': "abcd",
               'xqueue_body': score_msg}
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        feedback = {
            "success": True,
            "feedback": "Grader Feedback"
        }
        score_msg = {
            'correct': True,
            'score': 4,
            'msg': 'Grader Message',
            'feedback': json.dumps(feedback),
            'grader_type': 'IN',
            'grader_id': '1',
            'submission_id': '1',
            'success': True,
            'rubric_scores': [0],
            'rubric_scores_complete': True,
            'rubric_xml': etree.tostring(self.rubric)
        }
        get = {'queuekey': "abcd",
               'xqueue_body': json.dumps(score_msg)}
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_multiple(self):
        self.openendedmodule.new_history_entry("New Entry")
        feedback = {
            "success": True,
            "feedback": "Grader Feedback"
        }
        score_msg = {
            'correct': True,
            'score': [0, 1],
            'msg': 'Grader Message',
            'feedback': [json.dumps(feedback), json.dumps(feedback)],
            'grader_type': 'PE',
            'grader_id': ['1', '2'],
            'submission_id': '1',
            'success': True,
            'rubric_scores': [[0], [0]],
            'rubric_scores_complete': [True, True],
            'rubric_xml': [etree.tostring(self.rubric), etree.tostring(self.rubric)]
        }
        get = {'queuekey': "abcd",
               'xqueue_body': json.dumps(score_msg)}
        self.openendedmodule.update_score(get, self.test_system)


    def test_latest_post_assessment(self):
        self.update_score_single()
        assessment = self.openendedmodule.latest_post_assessment(self.test_system)
        self.assertFalse(assessment == '')
        # check for errors
        self.assertFalse('errors' in assessment)

    def test_update_score_single(self):
        self.update_score_single()
        score = self.openendedmodule.latest_score()
        self.assertEqual(score, 4)

    def test_update_score_multiple(self):
        """
        Tests that a score of [0, 1] gets aggregated to 1.  A change in behavior added by @jbau
        """
        self.update_score_multiple()
        score = self.openendedmodule.latest_score()
        self.assertEquals(score, 1)

    def test_open_ended_display(self):
        """
        Test storing answer with the open ended module.
        """

        # Create a module with no state yet.  Important that this start off as a blank slate.
        test_module = OpenEndedModule(self.test_system, self.location,
                                                self.definition, self.descriptor, self.static_data, self.metadata)

        saved_response = "Saved response."
        submitted_response = "Submitted response."

        # Initially, there will be no stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # And the initial answer to display will be an empty string.
        self.assertEqual(test_module.get_display_answer(), "")

        # Now, store an answer in the module.
        test_module.handle_ajax("store_answer", {'student_answer' : saved_response}, get_test_system())
        # The stored answer should now equal our response.
        self.assertEqual(test_module.stored_answer, saved_response)
        self.assertEqual(test_module.get_display_answer(), saved_response)

        # Mock out the send_to_grader function so it doesn't try to connect to the xqueue.
        test_module.send_to_grader = Mock(return_value=True)
        # Submit a student response to the question.
        test_module.handle_ajax(
            "save_answer",
            {"student_answer": submitted_response},
            get_test_system()
        )
        # Submitting an answer should clear the stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # Confirm that the answer is stored properly.
        self.assertEqual(test_module.latest_answer(), submitted_response)
class OpenEndedModuleTest(unittest.TestCase):
    """
    Test the open ended module class
    """
    location = Location(["i4x", "edX", "sa_test", "selfassessment",
                         "SampleQuestion"])

    metadata = json.dumps({'attempts': '10'})
    prompt = etree.XML("<prompt>This is a question prompt</prompt>")
    rubric = etree.XML('''<rubric>
        <category>
        <description>Response Quality</description>
        <option>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option>
        </category>
         </rubric>''')
    max_score = 4

    static_data = {
        'max_attempts': 20,
        'prompt': prompt,
        'rubric': rubric,
        'max_score': max_score,
        'display_name': 'Name',
        'accept_file_upload': False,
        'close_date': None,
        's3_interface': test_util_open_ended.S3_INTERFACE,
        'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
        'skip_basic_checks': False,
    }

    oeparam = etree.XML('''
      <openendedparam>
            <initial_display>Enter essay here.</initial_display>
            <answer_display>This is the answer.</answer_display>
            <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload>
        </openendedparam>
    ''')
    definition = {'oeparam': oeparam}
    descriptor = Mock()

    def setUp(self):
        self.test_system = get_test_system()

        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback,
                                   'default_queuename': 'testqueue',
                                   'waittime': 1}
        self.openendedmodule = OpenEndedModule(self.test_system, self.location,
                                               self.definition, self.descriptor, self.static_data, self.metadata)

    def test_message_post(self):
        get = {'feedback': 'feedback text',
               'submission_id': '1',
               'grader_id': '1',
               'score': 3}
        qtime = datetime.strftime(datetime.now(), xqueue_interface.dateformat)
        student_info = {'anonymous_student_id': self.test_system.anonymous_student_id,
                        'submission_time': qtime}
        contents = {
            'feedback': get['feedback'],
            'submission_id': int(get['submission_id']),
            'grader_id': int(get['grader_id']),
            'score': get['score'],
            'student_info': json.dumps(student_info)
        }

        result = self.openendedmodule.message_post(get, self.test_system)
        self.assertTrue(result['success'])
        # make sure it's actually sending something we want to the queue
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

        state = json.loads(self.openendedmodule.get_instance_state())
        self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE)

    def test_send_to_grader(self):
        submission = "This is a student submission"
        qtime = datetime.strftime(datetime.now(), xqueue_interface.dateformat)
        student_info = {'anonymous_student_id': self.test_system.anonymous_student_id,
                        'submission_time': qtime}
        contents = self.openendedmodule.payload.copy()
        contents.update({
            'student_info': json.dumps(student_info),
            'student_response': submission,
            'max_score': self.max_score
        })
        result = self.openendedmodule.send_to_grader(submission, self.test_system)
        self.assertTrue(result)
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        score_msg = {
            'correct': True,
            'score': 4,
            'msg': 'Grader Message',
            'feedback': "Grader Feedback"
        }
        get = {'queuekey': "abcd",
               'xqueue_body': score_msg}
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        feedback = {
            "success": True,
            "feedback": "Grader Feedback"
        }
        score_msg = {
            'correct': True,
            'score': 4,
            'msg': 'Grader Message',
            'feedback': json.dumps(feedback),
            'grader_type': 'IN',
            'grader_id': '1',
            'submission_id': '1',
            'success': True,
            'rubric_scores': [0],
            'rubric_scores_complete': True,
            'rubric_xml': etree.tostring(self.rubric)
        }
        get = {'queuekey': "abcd",
               'xqueue_body': json.dumps(score_msg)}
        self.openendedmodule.update_score(get, self.test_system)

    def test_latest_post_assessment(self):
        self.update_score_single()
        assessment = self.openendedmodule.latest_post_assessment(self.test_system)
        self.assertFalse(assessment == '')
        # check for errors
        self.assertFalse('errors' in assessment)

    def test_update_score(self):
        self.update_score_single()
        score = self.openendedmodule.latest_score()
        self.assertEqual(score, 4)
Example #7
0
class OpenEndedModuleTest(unittest.TestCase):
    """
    Test the open ended module class
    """
    location = Location(
        ["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"])

    metadata = json.dumps({'attempts': '10'})
    prompt = etree.XML("<prompt>This is a question prompt</prompt>")
    rubric = etree.XML('''<rubric>
        <category>
        <description>Response Quality</description>
        <option>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option>
        </category>
         </rubric>''')
    max_score = 4

    static_data = {
        'max_attempts': 20,
        'prompt': prompt,
        'rubric': rubric,
        'max_score': max_score,
        'display_name': 'Name',
        'accept_file_upload': False,
        'close_date': None,
        's3_interface': test_util_open_ended.S3_INTERFACE,
        'open_ended_grading_interface':
        test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
        'skip_basic_checks': False,
        'control': {
            'required_peer_grading': 1,
            'peer_grader_count': 1,
            'min_to_calibrate': 3,
            'max_to_calibrate': 6,
            'peer_grade_finished_submissions_when_none_pending': False,
        }
    }

    oeparam = etree.XML('''
      <openendedparam>
            <initial_display>Enter essay here.</initial_display>
            <answer_display>This is the answer.</answer_display>
            <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload>
        </openendedparam>
    ''')
    definition = {'oeparam': oeparam}
    descriptor = Mock()

    feedback = {"success": True, "feedback": "Grader Feedback"}

    single_score_msg = {
        'correct': True,
        'score': 4,
        'msg': 'Grader Message',
        'feedback': json.dumps(feedback),
        'grader_type': 'IN',
        'grader_id': '1',
        'submission_id': '1',
        'success': True,
        'rubric_scores': [0],
        'rubric_scores_complete': True,
        'rubric_xml': etree.tostring(rubric)
    }

    multiple_score_msg = {
        'correct': True,
        'score': [0, 1],
        'msg': 'Grader Message',
        'feedback': [json.dumps(feedback),
                     json.dumps(feedback)],
        'grader_type': 'PE',
        'grader_id': ['1', '2'],
        'submission_id': '1',
        'success': True,
        'rubric_scores': [[0], [0]],
        'rubric_scores_complete': [True, True],
        'rubric_xml': [etree.tostring(rubric),
                       etree.tostring(rubric)]
    }

    def setUp(self):
        self.test_system = get_test_system()
        self.test_system.open_ended_grading_interface = None
        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {
            'interface': self.mock_xqueue,
            'construct_callback': constructed_callback,
            'default_queuename': 'testqueue',
            'waittime': 1
        }
        self.openendedmodule = OpenEndedModule(self.test_system, self.location,
                                               self.definition,
                                               self.descriptor,
                                               self.static_data, self.metadata)

    def test_message_post(self):
        get = {
            'feedback': 'feedback text',
            'submission_id': '1',
            'grader_id': '1',
            'score': 3
        }
        qtime = datetime.strftime(datetime.now(UTC),
                                  xqueue_interface.dateformat)
        student_info = {
            'anonymous_student_id': self.test_system.anonymous_student_id,
            'submission_time': qtime
        }
        contents = {
            'feedback': get['feedback'],
            'submission_id': int(get['submission_id']),
            'grader_id': int(get['grader_id']),
            'score': get['score'],
            'student_info': json.dumps(student_info)
        }

        result = self.openendedmodule.message_post(get, self.test_system)
        self.assertTrue(result['success'])
        # make sure it's actually sending something we want to the queue
        self.mock_xqueue.send_to_queue.assert_called_with(
            body=json.dumps(contents), header=ANY)

        state = json.loads(self.openendedmodule.get_instance_state())
        self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE)

    def test_send_to_grader(self):
        submission = "This is a student submission"
        qtime = datetime.strftime(datetime.now(UTC),
                                  xqueue_interface.dateformat)
        student_info = {
            'anonymous_student_id': self.test_system.anonymous_student_id,
            'submission_time': qtime
        }
        contents = self.openendedmodule.payload.copy()
        contents.update({
            'student_info': json.dumps(student_info),
            'student_response': submission,
            'max_score': self.max_score
        })
        result = self.openendedmodule.send_to_grader(submission,
                                                     self.test_system)
        self.assertTrue(result)
        self.mock_xqueue.send_to_queue.assert_called_with(
            body=json.dumps(contents), header=ANY)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        get = {
            'queuekey': "abcd",
            'xqueue_body': json.dumps(self.single_score_msg)
        }
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_multiple(self):
        self.openendedmodule.new_history_entry("New Entry")
        get = {
            'queuekey': "abcd",
            'xqueue_body': json.dumps(self.multiple_score_msg)
        }
        self.openendedmodule.update_score(get, self.test_system)

    def test_latest_post_assessment(self):
        self.update_score_single()
        assessment = self.openendedmodule.latest_post_assessment(
            self.test_system)
        self.assertFalse(assessment == '')
        # check for errors
        self.assertFalse('errors' in assessment)

    def test_update_score_single(self):
        self.update_score_single()
        score = self.openendedmodule.latest_score()
        self.assertEqual(score, 4)

    def test_update_score_multiple(self):
        """
        Tests that a score of [0, 1] gets aggregated to 1.  A change in behavior added by @jbau
        """
        self.update_score_multiple()
        score = self.openendedmodule.latest_score()
        self.assertEquals(score, 1)

    @patch('xmodule.open_ended_grading_classes.open_ended_module.log.error')
    def test_update_score_nohistory(self, error_logger):
        """
        Tests error handling when there is no child_history
        """
        # NOTE that we are not creating any history items
        get = {
            'queuekey': "abcd",
            'xqueue_body': json.dumps(self.multiple_score_msg)
        }
        error_msg = (
            "Trying to update score without existing studentmodule child_history:\n"
            "   location: i4x://edX/sa_test/selfassessment/SampleQuestion\n"
            "   score: 1\n"
            "   grader_ids: [u'1', u'2']\n"
            "   submission_ids: [u'1', u'1']")
        self.openendedmodule.update_score(get, self.test_system)
        (msg, ), _ = error_logger.call_args
        self.assertTrue(error_logger.called)
        self.assertEqual(msg, error_msg)

    def test_open_ended_display(self):
        """
        Test storing answer with the open ended module.
        """

        # Create a module with no state yet.  Important that this start off as a blank slate.
        test_module = OpenEndedModule(self.test_system, self.location,
                                      self.definition, self.descriptor,
                                      self.static_data, self.metadata)

        saved_response = "Saved response."
        submitted_response = "Submitted response."

        # Initially, there will be no stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # And the initial answer to display will be an empty string.
        self.assertEqual(test_module.get_display_answer(), "")

        # Now, store an answer in the module.
        test_module.handle_ajax("store_answer",
                                {'student_answer': saved_response},
                                get_test_system())
        # The stored answer should now equal our response.
        self.assertEqual(test_module.stored_answer, saved_response)
        self.assertEqual(test_module.get_display_answer(), saved_response)

        # Mock out the send_to_grader function so it doesn't try to connect to the xqueue.
        test_module.send_to_grader = Mock(return_value=True)
        # Submit a student response to the question.
        test_module.handle_ajax("save_answer",
                                {"student_answer": submitted_response},
                                get_test_system())
        # Submitting an answer should clear the stored answer.
        self.assertEqual(test_module.stored_answer, None)
        # Confirm that the answer is stored properly.
        self.assertEqual(test_module.latest_answer(), submitted_response)
class OpenEndedModuleTest(unittest.TestCase):
    """
    Test the open ended module class
    """

    location = Location(["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"])

    metadata = json.dumps({"attempts": "10"})
    prompt = etree.XML("<prompt>This is a question prompt</prompt>")
    rubric = etree.XML(
        """<rubric>
        <category>
        <description>Response Quality</description>
        <option>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option>
        </category>
         </rubric>"""
    )
    max_score = 4

    static_data = {
        "max_attempts": 20,
        "prompt": prompt,
        "rubric": rubric,
        "max_score": max_score,
        "display_name": "Name",
        "accept_file_upload": False,
        "close_date": None,
        "s3_interface": test_util_open_ended.S3_INTERFACE,
        "open_ended_grading_interface": test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
        "skip_basic_checks": False,
        "control": {"required_peer_grading": 1, "peer_grader_count": 1, "min_to_calibrate": 3, "max_to_calibrate": 6},
    }

    oeparam = etree.XML(
        """
      <openendedparam>
            <initial_display>Enter essay here.</initial_display>
            <answer_display>This is the answer.</answer_display>
            <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload>
        </openendedparam>
    """
    )
    definition = {"oeparam": oeparam}
    descriptor = Mock()

    def setUp(self):
        self.test_system = get_test_system()
        self.test_system.open_ended_grading_interface = None
        self.test_system.location = self.location
        self.mock_xqueue = MagicMock()
        self.mock_xqueue.send_to_queue.return_value = (None, "Message")

        def constructed_callback(dispatch="score_update"):
            return dispatch

        self.test_system.xqueue = {
            "interface": self.mock_xqueue,
            "construct_callback": constructed_callback,
            "default_queuename": "testqueue",
            "waittime": 1,
        }
        self.openendedmodule = OpenEndedModule(
            self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata
        )

    def test_message_post(self):
        get = {"feedback": "feedback text", "submission_id": "1", "grader_id": "1", "score": 3}
        qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat)
        student_info = {"anonymous_student_id": self.test_system.anonymous_student_id, "submission_time": qtime}
        contents = {
            "feedback": get["feedback"],
            "submission_id": int(get["submission_id"]),
            "grader_id": int(get["grader_id"]),
            "score": get["score"],
            "student_info": json.dumps(student_info),
        }

        result = self.openendedmodule.message_post(get, self.test_system)
        self.assertTrue(result["success"])
        # make sure it's actually sending something we want to the queue
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

        state = json.loads(self.openendedmodule.get_instance_state())
        self.assertIsNotNone(state["child_state"], OpenEndedModule.DONE)

    def test_send_to_grader(self):
        submission = "This is a student submission"
        qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat)
        student_info = {"anonymous_student_id": self.test_system.anonymous_student_id, "submission_time": qtime}
        contents = self.openendedmodule.payload.copy()
        contents.update(
            {"student_info": json.dumps(student_info), "student_response": submission, "max_score": self.max_score}
        )
        result = self.openendedmodule.send_to_grader(submission, self.test_system)
        self.assertTrue(result)
        self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        score_msg = {"correct": True, "score": 4, "msg": "Grader Message", "feedback": "Grader Feedback"}
        get = {"queuekey": "abcd", "xqueue_body": score_msg}
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_single(self):
        self.openendedmodule.new_history_entry("New Entry")
        feedback = {"success": True, "feedback": "Grader Feedback"}
        score_msg = {
            "correct": True,
            "score": 4,
            "msg": "Grader Message",
            "feedback": json.dumps(feedback),
            "grader_type": "IN",
            "grader_id": "1",
            "submission_id": "1",
            "success": True,
            "rubric_scores": [0],
            "rubric_scores_complete": True,
            "rubric_xml": etree.tostring(self.rubric),
        }
        get = {"queuekey": "abcd", "xqueue_body": json.dumps(score_msg)}
        self.openendedmodule.update_score(get, self.test_system)

    def update_score_multiple(self):
        self.openendedmodule.new_history_entry("New Entry")
        feedback = {"success": True, "feedback": "Grader Feedback"}
        score_msg = {
            "correct": True,
            "score": [0, 1],
            "msg": "Grader Message",
            "feedback": [json.dumps(feedback), json.dumps(feedback)],
            "grader_type": "PE",
            "grader_id": ["1", "2"],
            "submission_id": "1",
            "success": True,
            "rubric_scores": [[0], [0]],
            "rubric_scores_complete": [True, True],
            "rubric_xml": [etree.tostring(self.rubric), etree.tostring(self.rubric)],
        }
        get = {"queuekey": "abcd", "xqueue_body": json.dumps(score_msg)}
        self.openendedmodule.update_score(get, self.test_system)

    def test_latest_post_assessment(self):
        self.update_score_single()
        assessment = self.openendedmodule.latest_post_assessment(self.test_system)
        self.assertFalse(assessment == "")
        # check for errors
        self.assertFalse("errors" in assessment)

    def test_update_score_single(self):
        self.update_score_single()
        score = self.openendedmodule.latest_score()
        self.assertEqual(score, 4)

    def test_update_score_multiple(self):
        """
        Tests that a score of [0, 1] gets aggregated to 1.  A change in behavior added by @jbau
        """
        self.update_score_multiple()
        score = self.openendedmodule.latest_score()
        self.assertEquals(score, 1)