Commit 6c9ad30e by Calen Pennington

Update open-ended tests to load the module between 'requests'

Under normal operation, XModules are reloaded on each request from a
student. CombinedOpenEnded modules have code that runs at initialization
that validates the students state. These changes makes that code run
during several long-form unit tests (testing CombinedOpenEnded across
multiple 'requests').

These tests are marked as expectedFailure because they now exhibit the
same failures as observed in [LMS-1493] (namely, the students state gets
reset, because CombinedOpenEnded interprets system.ajax_url raising an
error as meaning that the problem definition and the student answers are
in conflict)
parent 7a24f203
...@@ -93,7 +93,6 @@ class CombinedOpenEndedV1Module(): ...@@ -93,7 +93,6 @@ class CombinedOpenEndedV1Module():
Definition file should have one or many task blocks, a rubric block, and a prompt block. See DEFAULT_DATA in combined_open_ended_module for a sample. Definition file should have one or many task blocks, a rubric block, and a prompt block. See DEFAULT_DATA in combined_open_ended_module for a sample.
""" """
self.instance_state = instance_state self.instance_state = instance_state
self.display_name = instance_state.get('display_name', "Open Ended") self.display_name = instance_state.get('display_name', "Open Ended")
......
...@@ -726,76 +726,84 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): ...@@ -726,76 +726,84 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
assessment = [0, 1] assessment = [0, 1]
hint = "blah" hint = "blah"
def setUp(self): def get_module_system(self, descriptor):
self.test_system = get_test_system() test_system = get_test_system()
self.test_system.open_ended_grading_interface = None test_system.open_ended_grading_interface = None
self.test_system.xqueue['interface'] = Mock( test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"]) send_to_queue=Mock(side_effect=[1, "queued"])
) )
return test_system
def setUp(self):
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
def _handle_ajax(self, dispatch, content):
# Load the module from persistence
module = self._module()
# Call handle_ajax on the module
result = module.handle_ajax(dispatch, content)
# Persist the state
module.save()
return result
def _module(self):
return self.get_module_from_location(self.problem_location, COURSE)
def test_open_ended_load_and_save(self): def test_open_ended_load_and_save(self):
""" """
See if we can load the module and save an answer See if we can load the module and save an answer
@return: @return:
""" """
# Load the module
module = self.get_module_from_location(self.problem_location, COURSE)
# Try saving an answer # Try saving an answer
module.handle_ajax("save_answer", {"student_answer": self.answer}) self._handle_ajax("save_answer", {"student_answer": self.answer})
# Save our modifications to the underlying KeyValueStore so they can be persisted
module.save()
task_one_json = json.loads(module.task_states[0])
self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer)
module = self.get_module_from_location(self.problem_location, COURSE) task_one_json = json.loads(self._module().task_states[0])
task_one_json = json.loads(module.task_states[0])
self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer) self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer)
@unittest.expectedFailure
def test_open_ended_flow_reset(self): def test_open_ended_flow_reset(self):
""" """
Test the flow of the module if we complete the self assessment step and then reset Test the flow of the module if we complete the self assessment step and then reset
@return: @return:
""" """
assessment = [0, 1] assessment = [0, 1]
module = self.get_module_from_location(self.problem_location, COURSE)
# Simulate a student saving an answer # Simulate a student saving an answer
html = module.handle_ajax("get_html", {}) self._handle_ajax("get_html", {})
module.save() self._handle_ajax("save_answer", {"student_answer": self.answer})
module.handle_ajax("save_answer", {"student_answer": self.answer}) self._handle_ajax("get_html", {})
module.save()
html = module.handle_ajax("get_html", {})
module.save()
# Mock a student submitting an assessment # Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment) assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict) self._handle_ajax("save_assessment", assessment_dict)
module.save()
task_one_json = json.loads(module.task_states[0]) task_one_json = json.loads(self._module().task_states[0])
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
rubric = module.handle_ajax("get_combined_rubric", {})
module.save() self._handle_ajax("get_combined_rubric", {})
# Move to the next step in the problem # Move to the next step in the problem
module.handle_ajax("next_problem", {}) self._handle_ajax("next_problem", {})
module.save() self.assertEqual(self._module().current_task_number, 0)
self.assertEqual(module.current_task_number, 0)
html = module.render('student_view').content html = self._module().render('student_view').content
self.assertIsInstance(html, basestring) self.assertIsInstance(html, basestring)
rubric = module.handle_ajax("get_combined_rubric", {}) rubric = self._handle_ajax("get_combined_rubric", {})
module.save()
self.assertIsInstance(rubric, basestring) self.assertIsInstance(rubric, basestring)
self.assertEqual(module.state, "assessing")
module.handle_ajax("reset", {})
module.save()
self.assertEqual(module.current_task_number, 0)
self.assertEqual(self._module().state, "assessing")
self._handle_ajax("reset", {})
self.assertEqual(self._module().current_task_number, 0)
@unittest.expectedFailure
def test_open_ended_flow_correct(self): def test_open_ended_flow_correct(self):
""" """
Test a two step problem where the student first goes through the self assessment step, and then the Test a two step problem where the student first goes through the self assessment step, and then the
...@@ -803,42 +811,36 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): ...@@ -803,42 +811,36 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
@return: @return:
""" """
assessment = [1, 1] assessment = [1, 1]
# Load the module
module = self.get_module_from_location(self.problem_location, COURSE)
# Simulate a student saving an answer # Simulate a student saving an answer
module.handle_ajax("save_answer", {"student_answer": self.answer}) self._handle_ajax("save_answer", {"student_answer": self.answer})
module.save() status = self._handle_ajax("get_status", {})
status = module.handle_ajax("get_status", {})
module.save()
self.assertIsInstance(status, basestring) self.assertIsInstance(status, basestring)
# Mock a student submitting an assessment # Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment) assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict) self._handle_ajax("save_assessment", assessment_dict)
module.save()
task_one_json = json.loads(module.task_states[0]) task_one_json = json.loads(self._module().task_states[0])
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
# Move to the next step in the problem # Move to the next step in the problem
try: try:
module.handle_ajax("next_problem", {}) self._handle_ajax("next_problem", {})
module.save()
except GradingServiceError: except GradingServiceError:
# This error is okay. We don't have a grading service to connect to! # This error is okay. We don't have a grading service to connect to!
pass pass
self.assertEqual(module.current_task_number, 1) self.assertEqual(self._module().current_task_number, 1)
try: try:
module.render('student_view') self._module().render('student_view')
except GradingServiceError: except GradingServiceError:
# This error is okay. We don't have a grading service to connect to! # This error is okay. We don't have a grading service to connect to!
pass pass
# Try to get the rubric from the module # Try to get the rubric from the module
module.handle_ajax("get_combined_rubric", {}) self._handle_ajax("get_combined_rubric", {})
module.save()
# Make a fake reply from the queue # Make a fake reply from the queue
queue_reply = { queue_reply = {
...@@ -856,29 +858,26 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): ...@@ -856,29 +858,26 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
}) })
} }
module.handle_ajax("check_for_score", {}) self._handle_ajax("check_for_score", {})
module.save()
# Update the module with the fake queue reply # Update the module with the fake queue reply
module.handle_ajax("score_update", queue_reply) self._handle_ajax("score_update", queue_reply)
module.save()
module = self._module()
self.assertFalse(module.ready_to_reset) self.assertFalse(module.ready_to_reset)
self.assertEqual(module.current_task_number, 1) self.assertEqual(module.current_task_number, 1)
# Get html and other data client will request # Get html and other data client will request
module.render('student_view') module.render('student_view')
module.handle_ajax("skip_post_assessment", {}) self._handle_ajax("skip_post_assessment", {})
module.save()
# Get all results # Get all results
module.handle_ajax("get_combined_rubric", {}) self._handle_ajax("get_combined_rubric", {})
module.save()
# reset the problem # reset the problem
module.handle_ajax("reset", {}) self._handle_ajax("reset", {})
module.save() self.assertEqual(self._module().state, "initial")
self.assertEqual(module.state, "initial")
class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
...@@ -890,14 +889,33 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): ...@@ -890,14 +889,33 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
assessment = [0, 1] assessment = [0, 1]
hint = "blah" hint = "blah"
def setUp(self): def get_module_system(self, descriptor):
self.test_system = get_test_system() test_system = get_test_system()
self.test_system.open_ended_grading_interface = None test_system.open_ended_grading_interface = None
self.test_system.xqueue['interface'] = Mock( test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"]) send_to_queue=Mock(side_effect=[1, "queued"])
) )
return test_system
def setUp(self):
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
def _handle_ajax(self, dispatch, content):
# Load the module from persistence
module = self._module()
# Call handle_ajax on the module
result = module.handle_ajax(dispatch, content)
# Persist the state
module.save()
return result
def _module(self):
return self.get_module_from_location(self.problem_location, COURSE)
@unittest.expectedFailure
def test_reset_fail(self): def test_reset_fail(self):
""" """
Test the flow of the module if we complete the self assessment step and then reset Test the flow of the module if we complete the self assessment step and then reset
...@@ -905,39 +923,32 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): ...@@ -905,39 +923,32 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
@return: @return:
""" """
assessment = [0, 1] assessment = [0, 1]
module = self.get_module_from_location(self.problem_location, COURSE)
module.save()
# Simulate a student saving an answer # Simulate a student saving an answer
module.handle_ajax("save_answer", {"student_answer": self.answer}) self._handle_ajax("save_answer", {"student_answer": self.answer})
module.save()
# Mock a student submitting an assessment # Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment) assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict) self._handle_ajax("save_assessment", assessment_dict)
module.save() task_one_json = json.loads(self._module().task_states[0])
task_one_json = json.loads(module.task_states[0])
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
# Move to the next step in the problem # Move to the next step in the problem
module.handle_ajax("next_problem", {}) self._handle_ajax("next_problem", {})
module.save() self.assertEqual(self._module().current_task_number, 0)
self.assertEqual(module.current_task_number, 0)
html = module.render('student_view').content html = self._module().render('student_view').content
self.assertIsInstance(html, basestring) self.assertIsInstance(html, basestring)
# Module should now be done # Module should now be done
rubric = module.handle_ajax("get_combined_rubric", {}) rubric = self._handle_ajax("get_combined_rubric", {})
module.save()
self.assertIsInstance(rubric, basestring) self.assertIsInstance(rubric, basestring)
self.assertEqual(module.state, "done") self.assertEqual(self._module().state, "done")
# Try to reset, should fail because only 1 attempt is allowed # Try to reset, should fail because only 1 attempt is allowed
reset_data = json.loads(module.handle_ajax("reset", {})) reset_data = json.loads(self._handle_ajax("reset", {}))
module.save()
self.assertEqual(reset_data['success'], False) self.assertEqual(reset_data['success'], False)
class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore): class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore):
...@@ -951,13 +962,16 @@ class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore): ...@@ -951,13 +962,16 @@ class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore):
answer_link = "http://www.edx.org" answer_link = "http://www.edx.org"
autolink_tag = "<a href=" autolink_tag = "<a href="
def setUp(self): def get_module_system(self, descriptor):
self.test_system = get_test_system() test_system = get_test_system()
self.test_system.open_ended_grading_interface = None test_system.open_ended_grading_interface = None
self.test_system.s3_interface = test_util_open_ended.S3_INTERFACE test_system.s3_interface = test_util_open_ended.S3_INTERFACE
self.test_system.xqueue['interface'] = Mock( test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"]) send_to_queue=Mock(side_effect=[1, "queued"])
) )
return test_system
def setUp(self):
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
def test_file_upload_fail(self): def test_file_upload_fail(self):
......
...@@ -41,13 +41,16 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore): ...@@ -41,13 +41,16 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
}) })
save_dict.extend(('rubric_scores[]', val) for val in (0, 1)) save_dict.extend(('rubric_scores[]', val) for val in (0, 1))
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
return test_system
def setUp(self): def setUp(self):
""" """
Create a peer grading module from a test system Create a peer grading module from a test system
@return: @return:
""" """
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
self.peer_grading = self.get_module_from_location(self.problem_location, COURSE) self.peer_grading = self.get_module_from_location(self.problem_location, COURSE)
self.coe = self.get_module_from_location(self.coe_location, COURSE) self.coe = self.get_module_from_location(self.coe_location, COURSE)
...@@ -173,13 +176,16 @@ class PeerGradingModuleScoredTest(unittest.TestCase, DummyModulestore): ...@@ -173,13 +176,16 @@ class PeerGradingModuleScoredTest(unittest.TestCase, DummyModulestore):
["i4x", "edX", "open_ended", "peergrading", "PeerGradingScored"] ["i4x", "edX", "open_ended", "peergrading", "PeerGradingScored"]
) )
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
return test_system
def setUp(self): def setUp(self):
""" """
Create a peer grading module from a test system Create a peer grading module from a test system
@return: @return:
""" """
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
def test_metadata_load(self): def test_metadata_load(self):
...@@ -213,12 +219,15 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore): ...@@ -213,12 +219,15 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
coe_location = Location(["i4x", "edX", "open_ended", "combinedopenended", coe_location = Location(["i4x", "edX", "open_ended", "combinedopenended",
"SampleQuestion"]) "SampleQuestion"])
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
return test_system
def setUp(self): def setUp(self):
""" """
Create a peer grading module from a test system. Create a peer grading module from a test system.
""" """
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
@property @property
...@@ -270,14 +279,16 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore): ...@@ -270,14 +279,16 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
else: else:
pg_descriptor.get_required_module_descriptors = lambda: [] pg_descriptor.get_required_module_descriptors = lambda: []
test_system = self.get_module_system(pg_descriptor)
# Initialize the peer grading module. # Initialize the peer grading module.
peer_grading = PeerGradingModule( peer_grading = PeerGradingModule(
pg_descriptor, pg_descriptor,
self.test_system, test_system,
self.field_data, self.field_data,
self.scope_ids, self.scope_ids,
) )
self.test_system.xmodule_instance = peer_grading test_system.xmodule_instance = peer_grading
return peer_grading return peer_grading
...@@ -384,13 +395,16 @@ class PeerGradingModuleTrackChangesTest(unittest.TestCase, DummyModulestore): ...@@ -384,13 +395,16 @@ class PeerGradingModuleTrackChangesTest(unittest.TestCase, DummyModulestore):
mock_track_changes_problem = Mock(side_effect=[MockedTrackChangesProblem()]) mock_track_changes_problem = Mock(side_effect=[MockedTrackChangesProblem()])
pgm_location = Location(["i4x", "edX", "open_ended", "peergrading", "PeerGradingSample"]) pgm_location = Location(["i4x", "edX", "open_ended", "peergrading", "PeerGradingSample"])
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
return test_system
def setUp(self): def setUp(self):
""" """
Create a peer grading module from a test system Create a peer grading module from a test system
@return: @return:
""" """
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE) self.setup_modulestore(COURSE)
self.peer_grading = self.get_module_from_location(self.pgm_location, COURSE) self.peer_grading = self.get_module_from_location(self.pgm_location, COURSE)
......
...@@ -78,7 +78,9 @@ class DummyModulestore(object): ...@@ -78,7 +78,9 @@ class DummyModulestore(object):
""" """
A mixin that allows test classes to have convenience functions to get a module given a location A mixin that allows test classes to have convenience functions to get a module given a location
""" """
get_test_system = get_test_system()
def get_module_system(self, descriptor):
raise NotImplementedError("Sub-tests must specify how to generate a module-system")
def setup_modulestore(self, name): def setup_modulestore(self, name):
self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name]) self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name])
...@@ -93,7 +95,7 @@ class DummyModulestore(object): ...@@ -93,7 +95,7 @@ class DummyModulestore(object):
if not isinstance(location, Location): if not isinstance(location, Location):
location = Location(location) location = Location(location)
descriptor = self.modulestore.get_instance(course.id, location, depth=None) descriptor = self.modulestore.get_instance(course.id, location, depth=None)
descriptor.xmodule_runtime = self.test_system descriptor.xmodule_runtime = self.get_module_system(descriptor)
return descriptor return descriptor
# Task state for a module with self assessment then instructor assessment. # Task state for a module with self assessment then instructor assessment.
......
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