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():
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.display_name = instance_state.get('display_name', "Open Ended")
......
......@@ -726,76 +726,84 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
assessment = [0, 1]
hint = "blah"
def setUp(self):
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.test_system.xqueue['interface'] = Mock(
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"])
)
return test_system
def setUp(self):
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):
"""
See if we can load the module and save an answer
@return:
"""
# Load the module
module = self.get_module_from_location(self.problem_location, COURSE)
# Try saving an answer
module.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)
self._handle_ajax("save_answer", {"student_answer": self.answer})
module = self.get_module_from_location(self.problem_location, COURSE)
task_one_json = json.loads(module.task_states[0])
task_one_json = json.loads(self._module().task_states[0])
self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer)
@unittest.expectedFailure
def test_open_ended_flow_reset(self):
"""
Test the flow of the module if we complete the self assessment step and then reset
@return:
"""
assessment = [0, 1]
module = self.get_module_from_location(self.problem_location, COURSE)
# Simulate a student saving an answer
html = module.handle_ajax("get_html", {})
module.save()
module.handle_ajax("save_answer", {"student_answer": self.answer})
module.save()
html = module.handle_ajax("get_html", {})
module.save()
self._handle_ajax("get_html", {})
self._handle_ajax("save_answer", {"student_answer": self.answer})
self._handle_ajax("get_html", {})
# Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict)
module.save()
task_one_json = json.loads(module.task_states[0])
self._handle_ajax("save_assessment", assessment_dict)
task_one_json = json.loads(self._module().task_states[0])
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
module.handle_ajax("next_problem", {})
module.save()
self.assertEqual(module.current_task_number, 0)
self._handle_ajax("next_problem", {})
self.assertEqual(self._module().current_task_number, 0)
html = module.render('student_view').content
html = self._module().render('student_view').content
self.assertIsInstance(html, basestring)
rubric = module.handle_ajax("get_combined_rubric", {})
module.save()
rubric = self._handle_ajax("get_combined_rubric", {})
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):
"""
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):
@return:
"""
assessment = [1, 1]
# Load the module
module = self.get_module_from_location(self.problem_location, COURSE)
# Simulate a student saving an answer
module.handle_ajax("save_answer", {"student_answer": self.answer})
module.save()
status = module.handle_ajax("get_status", {})
module.save()
self._handle_ajax("save_answer", {"student_answer": self.answer})
status = self._handle_ajax("get_status", {})
self.assertIsInstance(status, basestring)
# Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict)
module.save()
task_one_json = json.loads(module.task_states[0])
self._handle_ajax("save_assessment", assessment_dict)
task_one_json = json.loads(self._module().task_states[0])
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
# Move to the next step in the problem
try:
module.handle_ajax("next_problem", {})
module.save()
self._handle_ajax("next_problem", {})
except GradingServiceError:
# This error is okay. We don't have a grading service to connect to!
pass
self.assertEqual(module.current_task_number, 1)
self.assertEqual(self._module().current_task_number, 1)
try:
module.render('student_view')
self._module().render('student_view')
except GradingServiceError:
# This error is okay. We don't have a grading service to connect to!
pass
# Try to get the rubric from the module
module.handle_ajax("get_combined_rubric", {})
module.save()
self._handle_ajax("get_combined_rubric", {})
# Make a fake reply from the queue
queue_reply = {
......@@ -856,29 +858,26 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
})
}
module.handle_ajax("check_for_score", {})
module.save()
self._handle_ajax("check_for_score", {})
# Update the module with the fake queue reply
module.handle_ajax("score_update", queue_reply)
module.save()
self._handle_ajax("score_update", queue_reply)
module = self._module()
self.assertFalse(module.ready_to_reset)
self.assertEqual(module.current_task_number, 1)
# Get html and other data client will request
module.render('student_view')
module.handle_ajax("skip_post_assessment", {})
module.save()
self._handle_ajax("skip_post_assessment", {})
# Get all results
module.handle_ajax("get_combined_rubric", {})
module.save()
self._handle_ajax("get_combined_rubric", {})
# reset the problem
module.handle_ajax("reset", {})
module.save()
self.assertEqual(module.state, "initial")
self._handle_ajax("reset", {})
self.assertEqual(self._module().state, "initial")
class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
......@@ -890,14 +889,33 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
assessment = [0, 1]
hint = "blah"
def setUp(self):
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.test_system.xqueue['interface'] = Mock(
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"])
)
return test_system
def setUp(self):
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):
"""
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):
@return:
"""
assessment = [0, 1]
module = self.get_module_from_location(self.problem_location, COURSE)
module.save()
# Simulate a student saving an answer
module.handle_ajax("save_answer", {"student_answer": self.answer})
module.save()
self._handle_ajax("save_answer", {"student_answer": self.answer})
# Mock a student submitting an assessment
assessment_dict = MultiDict({'assessment': sum(assessment)})
assessment_dict.extend(('score_list[]', val) for val in assessment)
module.handle_ajax("save_assessment", assessment_dict)
module.save()
task_one_json = json.loads(module.task_states[0])
self._handle_ajax("save_assessment", assessment_dict)
task_one_json = json.loads(self._module().task_states[0])
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
# Move to the next step in the problem
module.handle_ajax("next_problem", {})
module.save()
self.assertEqual(module.current_task_number, 0)
self._handle_ajax("next_problem", {})
self.assertEqual(self._module().current_task_number, 0)
html = module.render('student_view').content
html = self._module().render('student_view').content
self.assertIsInstance(html, basestring)
# Module should now be done
rubric = module.handle_ajax("get_combined_rubric", {})
module.save()
rubric = self._handle_ajax("get_combined_rubric", {})
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
reset_data = json.loads(module.handle_ajax("reset", {}))
module.save()
reset_data = json.loads(self._handle_ajax("reset", {}))
self.assertEqual(reset_data['success'], False)
class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore):
......@@ -951,13 +962,16 @@ class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore):
answer_link = "http://www.edx.org"
autolink_tag = "<a href="
def setUp(self):
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.test_system.s3_interface = test_util_open_ended.S3_INTERFACE
self.test_system.xqueue['interface'] = Mock(
def get_module_system(self, descriptor):
test_system = get_test_system()
test_system.open_ended_grading_interface = None
test_system.s3_interface = test_util_open_ended.S3_INTERFACE
test_system.xqueue['interface'] = Mock(
send_to_queue=Mock(side_effect=[1, "queued"])
)
return test_system
def setUp(self):
self.setup_modulestore(COURSE)
def test_file_upload_fail(self):
......
......@@ -41,13 +41,16 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
})
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):
"""
Create a peer grading module from a test system
@return:
"""
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE)
self.peer_grading = self.get_module_from_location(self.problem_location, COURSE)
self.coe = self.get_module_from_location(self.coe_location, COURSE)
......@@ -173,13 +176,16 @@ class PeerGradingModuleScoredTest(unittest.TestCase, DummyModulestore):
["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):
"""
Create a peer grading module from a test system
@return:
"""
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE)
def test_metadata_load(self):
......@@ -213,12 +219,15 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
coe_location = Location(["i4x", "edX", "open_ended", "combinedopenended",
"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):
"""
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)
@property
......@@ -270,14 +279,16 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
else:
pg_descriptor.get_required_module_descriptors = lambda: []
test_system = self.get_module_system(pg_descriptor)
# Initialize the peer grading module.
peer_grading = PeerGradingModule(
pg_descriptor,
self.test_system,
test_system,
self.field_data,
self.scope_ids,
)
self.test_system.xmodule_instance = peer_grading
test_system.xmodule_instance = peer_grading
return peer_grading
......@@ -384,13 +395,16 @@ class PeerGradingModuleTrackChangesTest(unittest.TestCase, DummyModulestore):
mock_track_changes_problem = Mock(side_effect=[MockedTrackChangesProblem()])
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):
"""
Create a peer grading module from a test system
@return:
"""
self.test_system = get_test_system()
self.test_system.open_ended_grading_interface = None
self.setup_modulestore(COURSE)
self.peer_grading = self.get_module_from_location(self.pgm_location, COURSE)
......
......@@ -78,7 +78,9 @@ class DummyModulestore(object):
"""
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):
self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name])
......@@ -93,7 +95,7 @@ class DummyModulestore(object):
if not isinstance(location, Location):
location = Location(location)
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
# 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