Commit 5cbcb347 by Brian Wilson

Suppress variant from non-submission problem-check events if not rerandomize.

Change-Id: I44b132e333e20fb32d032722406b61748a5a71fd
parent 846e0424
...@@ -175,7 +175,7 @@ class LastProblemCheckEventMixin(object): ...@@ -175,7 +175,7 @@ class LastProblemCheckEventMixin(object):
if answer_id not in correct_map: if answer_id not in correct_map:
log.error("Unexpected answer_id %s not in correct_map: %s", answer_id, event) log.error("Unexpected answer_id %s not in correct_map: %s", answer_id, event)
continue continue
correctness = correct_map[answer_id].get('correctness') in ['correct'] correctness = correct_map[answer_id].get('correctness') == 'correct'
variant = event.get('state', {}).get('seed') variant = event.get('state', {}).get('seed')
...@@ -275,7 +275,8 @@ class AnswerDistributionPerCourseMixin(object): ...@@ -275,7 +275,8 @@ class AnswerDistributionPerCourseMixin(object):
problem_id = most_recent_answer.get('problem_id') problem_id = most_recent_answer.get('problem_id')
problem_display_name = most_recent_answer.get('problem_display_name') problem_display_name = most_recent_answer.get('problem_display_name')
most_recent_question = most_recent_answer.get('question', '') most_recent_question = most_recent_answer.get('question', '')
answer_uses_code = ('answer_value_id' in most_recent_answer) answer_uses_value_id = ('answer_value_id' in most_recent_answer)
answer_uses_variant = (most_recent_answer.get('variant', '') != '')
answer_dist = {} answer_dist = {}
for _timestamp, value_string in reversed(values): for _timestamp, value_string in reversed(values):
answer = json.loads(value_string) answer = json.loads(value_string)
...@@ -291,7 +292,7 @@ class AnswerDistributionPerCourseMixin(object): ...@@ -291,7 +292,7 @@ class AnswerDistributionPerCourseMixin(object):
# We only want this from the most recent answer that has # We only want this from the most recent answer that has
# this value. # this value.
if answer_grouping_key not in answer_dist: if answer_grouping_key not in answer_dist:
if answer_uses_code: if answer_uses_value_id:
# The most recent overall answer indicates that # The most recent overall answer indicates that
# the code should be returned as such. If this # the code should be returned as such. If this
# particular answer did not have 'submission' # particular answer did not have 'submission'
...@@ -317,19 +318,21 @@ class AnswerDistributionPerCourseMixin(object): ...@@ -317,19 +318,21 @@ class AnswerDistributionPerCourseMixin(object):
# If there is no variant, then the question should be # If there is no variant, then the question should be
# the same, and we want to go with the most recently # the same, and we want to go with the most recently
# defined value. # defined value.
if answer.get('variant'): if answer_uses_variant:
question = answer.get('question', '') question = answer.get('question', '')
variant = answer.get('variant') or ''
else: else:
question = most_recent_question question = most_recent_question
variant = ''
# Key values here should match those used in get_column_order(). # Key values here should match those used in get_column_order().
answer_dist[answer_grouping_key] = { answer_dist[answer_grouping_key] = {
'ModuleID': problem_id, 'ModuleID': problem_id,
'PartID': answer_id, 'PartID': answer_id,
'ValueID': value_id, 'ValueID': value_id or '',
'AnswerValue': answer_value, 'AnswerValue': answer_value or '',
'Variant': answer.get('variant'), 'Variant': variant,
'Problem Display Name': problem_display_name, 'Problem Display Name': problem_display_name or '',
'Question': question, 'Question': question,
'Correct Answer': '1' if answer.get('correct') else '0', 'Correct Answer': '1' if answer.get('correct') else '0',
'Count': 0, 'Count': 0,
......
...@@ -28,6 +28,7 @@ def main(): ...@@ -28,6 +28,7 @@ def main():
sys.exit(return_code) sys.exit(return_code)
def run_task_playbook(arguments, uid): def run_task_playbook(arguments, uid):
""" """
Execute the ansible playbook that triggers and monitors the remote task execution. Execute the ansible playbook that triggers and monitors the remote task execution.
...@@ -39,6 +40,7 @@ def run_task_playbook(arguments, uid): ...@@ -39,6 +40,7 @@ def run_task_playbook(arguments, uid):
extra_vars = convert_args_to_extra_vars(arguments, uid) extra_vars = convert_args_to_extra_vars(arguments, uid)
return run_ansible(('task.yml', '-e', extra_vars), arguments.verbose, executable='ansible-playbook') return run_ansible(('task.yml', '-e', extra_vars), arguments.verbose, executable='ansible-playbook')
def convert_args_to_extra_vars(arguments, uid): def convert_args_to_extra_vars(arguments, uid):
""" """
Generate the set of variables that need to be passed in to ansible since they are expected to be set by the Generate the set of variables that need to be passed in to ansible since they are expected to be set by the
...@@ -60,6 +62,7 @@ def convert_args_to_extra_vars(arguments, uid): ...@@ -60,6 +62,7 @@ def convert_args_to_extra_vars(arguments, uid):
extra_vars['wait_for_task'] = True extra_vars['wait_for_task'] = True
return ' '.join(["{}='{}'".format(k, extra_vars[k]) for k in extra_vars]) return ' '.join(["{}='{}'".format(k, extra_vars[k]) for k in extra_vars])
def run_ansible(args, verbose, executable='ansible'): def run_ansible(args, verbose, executable='ansible'):
""" """
Execute ansible passing in the provided arguments. Execute ansible passing in the provided arguments.
...@@ -95,6 +98,7 @@ def run_ansible(args, verbose, executable='ansible'): ...@@ -95,6 +98,7 @@ def run_ansible(args, verbose, executable='ansible'):
return proc.returncode return proc.returncode
def download_logs(arguments, uid): def download_logs(arguments, uid):
""" """
Connect to the remote machine and download the logs produced by luigi. Connect to the remote machine and download the logs produced by luigi.
......
...@@ -443,13 +443,13 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -443,13 +443,13 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
def _get_expected_output(self, answer_data, **kwargs): def _get_expected_output(self, answer_data, **kwargs):
"""Get an expected reducer output based on the input.""" """Get an expected reducer output based on the input."""
expected_output = { expected_output = {
"Problem Display Name": answer_data.get('problem_display_name'), "Problem Display Name": answer_data.get('problem_display_name') or "",
"Count": 1, "Count": 1,
"PartID": self.answer_id, "PartID": self.answer_id,
"Question": answer_data.get('question'), "Question": answer_data.get('question') or "",
"AnswerValue": answer_data.get('answer'), "AnswerValue": answer_data.get('answer') or answer_data.get('answer_value_id') or "",
"ValueID": "", "ValueID": "",
"Variant": answer_data.get('variant'), "Variant": answer_data.get('variant') or "",
"Correct Answer": "1" if answer_data['correct'] else '0', "Correct Answer": "1" if answer_data['correct'] else '0',
"ModuleID": self.problem_id, "ModuleID": self.problem_id,
} }
...@@ -551,6 +551,23 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -551,6 +551,23 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
expected_output_2 = self._get_expected_output(answer_data_2) expected_output_2 = self._get_expected_output(answer_data_2)
self._check_output([input_data_1, input_data_2], (expected_output_1, expected_output_2)) self._check_output([input_data_1, input_data_2], (expected_output_1, expected_output_2))
def test_two_answer_event_different_old_and_new(self):
answer_data_1 = self._get_non_submission_answer_data(answer_value_id="first")
answer_data_2 = self._get_answer_data(problem_display_name=self.problem_display_name)
input_data_1 = (self.earlier_timestamp, json.dumps(answer_data_1))
input_data_2 = (self.timestamp, json.dumps(answer_data_2))
expected_output_2 = self._get_expected_output(answer_data_2)
# An older non-submission-based event should inherit some
# information from a newer submission-based event.
# In particular, the Variant, the Question, and Problem Display Name.
expected_output_1 = self._get_expected_output(
answer_data_1,
Variant="",
Question=expected_output_2['Question'],
)
expected_output_1['Problem Display Name'] = expected_output_2['Problem Display Name']
self._check_output([input_data_1, input_data_2], (expected_output_1, expected_output_2))
def test_two_answer_event_different_variant(self): def test_two_answer_event_different_variant(self):
answer_data_1 = self._get_answer_data(variant=123) answer_data_1 = self._get_answer_data(variant=123)
answer_data_2 = self._get_answer_data(variant=456) answer_data_2 = self._get_answer_data(variant=456)
......
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