def test_cannot_update_question_with_no_change_list(self): with self.assertRaisesRegexp( Exception, 'Unexpected error: received an invalid change list when trying to ' 'save question'): question_services.update_question(self.editor_id, self.question_id, [], 'updated question data')
def put(self, question_id): """Updates properties of the given question.""" commit_message = self.payload.get('commit_message') if not commit_message: raise self.PageNotFoundException if (commit_message is not None and len(commit_message) > constants.MAX_COMMIT_MESSAGE_LENGTH): raise self.InvalidInputException( 'Commit messages must be at most %s characters long.' % constants.MAX_COMMIT_MESSAGE_LENGTH) if not self.payload.get('change_list'): raise self.PageNotFoundException change_list = [ question_domain.QuestionChange(change) for change in self.payload.get('change_list') ] for change in change_list: if (change.cmd == question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION): raise self.InvalidInputException question_services.update_question(self.user_id, question_id, change_list, commit_message) question_dict = question_services.get_question_by_id( question_id).to_dict() self.render_json({'question_dict': question_dict})
def put(self, question_id): """Updates properties of the given question.""" if not constants.ENABLE_NEW_STRUCTURES: raise self.PageNotFoundException question = question_services.get_question_by_id(question_id, strict=False) if question is None: raise self.PageNotFoundException( 'The question with the given id doesn\'t exist.') commit_message = self.payload.get('commit_message') if not question_id: raise self.PageNotFoundException if not commit_message: raise self.PageNotFoundException if not self.payload.get('change_list'): raise self.PageNotFoundException change_list = [ question_domain.QuestionChange(change) for change in self.payload.get('change_list') ] for change in change_list: if (change.cmd == question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION): raise self.InvalidInputException question_services.update_question(self.user_id, question_id, change_list, commit_message) question_dict = question_services.get_question_by_id( question_id).to_dict() return self.render_json({'question_dict': question_dict})
def map(item): if item.deleted: yield (QuestionMigrationOneOffJob._DELETED_KEY, 1) return # Note: the read will bring the question up to the newest version. question = question_services.get_question_by_id(item.id) try: question.validate() except Exception as e: logging.error('Question %s failed validation: %s' % (item.id, e)) yield (QuestionMigrationOneOffJob._ERROR_KEY, 'Question %s failed validation: %s' % (item.id, e)) return # Write the new question into the datastore if it's different from # the old version. if (item.question_state_data_schema_version <= feconf.CURRENT_STATE_SCHEMA_VERSION): commit_cmds = [ question_domain.QuestionChange({ 'cmd': question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION, # pylint: disable=line-too-long 'from_version': item.question_state_data_schema_version, 'to_version': feconf.CURRENT_STATE_SCHEMA_VERSION }) ] question_services.update_question( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Update question state schema version to %d.' % (feconf.CURRENT_STATE_SCHEMA_VERSION)) yield (QuestionMigrationOneOffJob._MIGRATED_KEY, 1)
def test_update_question(self): question_data = self._create_valid_question_data('ABC') question_id = 'dummy' question_data_schema_version = 1 language_code = 'en' question = question_domain.Question(question_id, question_data, question_data_schema_version, language_code) new_question_data = self._create_valid_question_data('DEF') question_id = question_services.add_question(self.owner_id, question) change_dict = { 'cmd': 'update_question_property', 'property_name': 'question_data', 'new_value': new_question_data, 'old_value': question_data } change_list = [question_domain.QuestionChange(change_dict)] question_services.update_question(self.owner_id, question_id, change_list, ('updated question data')) model = question_models.QuestionModel.get(question_id) self.assertEqual(model.question_data, new_question_data) self.assertEqual(model.question_data_schema_version, question_data_schema_version) self.assertEqual(model.language_code, language_code)
def test_update_question(self): state = exp_domain.State.create_default_state('ABC') question_data = state.to_dict() question_id = 'dummy' title = 'A Question' question_data_schema_version = 1 collection_id = 'col1' language_code = 'en' question = question_domain.Question(question_id, title, question_data, question_data_schema_version, collection_id, language_code) question_id = question_services.add_question(self.owner_id, question) change_dict = { 'cmd': 'update_question_property', 'property_name': 'title', 'new_value': 'ABC', 'old_value': 'A Question' } change_list = [question_domain.QuestionChange(change_dict)] question_services.update_question(self.owner_id, question_id, change_list, 'updated title') model = question_models.QuestionModel.get(question_id) self.assertEqual(model.title, 'ABC') self.assertEqual(model.question_data, question_data) self.assertEqual(model.question_data_schema_version, question_data_schema_version) self.assertEqual(model.collection_id, collection_id) self.assertEqual(model.language_code, language_code)
def test_audit_job_failure(self): """Test that the audit job catches errors that would otherwise occur during the migration. """ swap_states_schema_36 = self.swap( feconf, 'CURRENT_STATE_SCHEMA_VERSION', 36) with swap_states_schema_36: self.save_new_question( self.QUESTION_ID, self.albert_id, self._create_valid_question_data('ABC'), [self.skill_id]) # Bring the main question to the latest schema. latest_schema_version = python_utils.UNICODE( feconf.CURRENT_STATE_SCHEMA_VERSION) migration_change_list = [ question_domain.QuestionChange({ 'cmd': ( question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION ), 'from_version': '37', 'to_version': latest_schema_version }) ] question_services.update_question( self.albert_id, self.QUESTION_ID, migration_change_list, 'Ran Question Migration job.') question_model = question_models.QuestionModel.get(self.QUESTION_ID) self.assertEqual( question_model.question_state_data_schema_version, feconf.CURRENT_STATE_SCHEMA_VERSION) # Make a mock conversion function that raises an error when trying to # convert the old snapshot. mock_conversion = classmethod( lambda cls, question_dict: question_dict['property_that_dne']) with self.swap( question_domain.Question, '_convert_state_v36_dict_to_v37_dict', mock_conversion ): job_id = ( question_jobs_one_off.QuestionSnapshotsMigrationAuditJob. create_new()) question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.enqueue( job_id) self.process_and_flush_pending_mapreduce_tasks() actual_output = ( question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.get_output( job_id)) expected_output_message = ( u'[u\'MIGRATION_ERROR\', [u"Question snapshot %s-1 failed ' 'migration to state v37: u\'property_that_dne\'"]]' % self.QUESTION_ID ) self.assertIn(expected_output_message, actual_output)
def test_cannot_update_question_with_no_commit_message(self): new_question_data = self._create_valid_question_data('DEF') change_dict = { 'cmd': 'update_question_property', 'property_name': 'question_state_data', 'new_value': new_question_data.to_dict(), 'old_value': self.question.question_state_data.to_dict() } change_list = [question_domain.QuestionChange(change_dict)] with self.assertRaisesRegexp( Exception, 'Expected a commit message, received none.'): question_services.update_question( self.editor_id, self.question_id, change_list, None)
def put(self, question_id): """Handles PUT requests.""" commit_message = self.payload.get('commit_message') if not question_id: raise self.PageNotFoundException if not commit_message: raise self.PageNotFoundException if not self.payload.get('change_list'): raise self.PageNotFoundException change_list = [ question_domain.QuestionChange(change) for change in json.loads(self.payload.get('change_list')) ] question_services.update_question(self.user_id, question_id, change_list, commit_message) return self.render_json({'question_id': question_id})
def test_audit_job_success(self): """Test that the audit job runs correctly on snapshots that use a previous state schema. """ swap_states_schema_36 = self.swap( feconf, 'CURRENT_STATE_SCHEMA_VERSION', 36) with swap_states_schema_36: question = self.save_new_question( self.QUESTION_ID, self.albert_id, self._create_valid_question_data('ABC'), [self.skill_id]) self.assertLess(question.question_state_data_schema_version, 37) # Bring the main question to schema version 37. migration_change_list = [ question_domain.QuestionChange({ 'cmd': ( question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION ), 'from_version': '36', 'to_version': '37' }) ] swap_states_schema_37 = self.swap( feconf, 'CURRENT_STATE_SCHEMA_VERSION', 37) with swap_states_schema_37: question_services.update_question( self.albert_id, self.QUESTION_ID, migration_change_list, 'Ran Question Migration job.') question_model = question_models.QuestionModel.get(self.QUESTION_ID) self.assertEqual( question_model.question_state_data_schema_version, 37) job_id = ( question_jobs_one_off.QuestionSnapshotsMigrationAuditJob. create_new()) question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.enqueue( job_id) self.process_and_flush_pending_mapreduce_tasks() actual_output = ( question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.get_output( job_id)) expected_output = [ '[u\'SUCCESS\', 1]', '[u\'SUCCESS - Snapshot is already at latest schema version\', 1]' ] self.assertEqual(sorted(actual_output), sorted(expected_output))
def test_update_question_language_code(self): self.assertEqual(self.question.language_code, 'en') change_dict = { 'cmd': 'update_question_property', 'property_name': 'language_code', 'new_value': 'bn', 'old_value': 'en' } change_list = [question_domain.QuestionChange(change_dict)] question_services.update_question( self.editor_id, self.question_id, change_list, 'updated question language code') question = question_services.get_question_by_id(self.question_id) self.assertEqual(question.language_code, 'bn') self.assertEqual(question.version, 2)
def test_update_question(self): new_question_data = self._create_valid_question_data('DEF') change_dict = { 'cmd': 'update_question_property', 'property_name': 'question_state_data', 'new_value': new_question_data.to_dict(), 'old_value': self.question.question_state_data.to_dict() } change_list = [question_domain.QuestionChange(change_dict)] question_services.update_question(self.editor_id, self.question_id, change_list, 'updated question data') question = question_services.get_question_by_id(self.question_id) self.assertEqual(question.question_state_data.to_dict(), new_question_data.to_dict()) self.assertEqual(question.version, 2)
def test_cannot_update_question_with_invalid_change_list(self): observed_log_messages = [] def _mock_logging_function(msg, *args): """Mocks logging.error().""" observed_log_messages.append(msg % args) logging_swap = self.swap(logging, 'error', _mock_logging_function) assert_raises_context_manager = self.assertRaises(Exception) with logging_swap, assert_raises_context_manager: question_services.update_question( self.editor_id, self.question_id, 'invalid_change_list', 'updated question language code') self.assertEqual(len(observed_log_messages), 1) self.assertRegexpMatches( observed_log_messages[0], 'object has no attribute \'cmd\' %s ' 'invalid_change_list' % self.question_id)
def test_migration_job_succeeds_on_default_question(self): swap_states_schema_version_37 = self.swap( feconf, 'CURRENT_STATE_SCHEMA_VERSION', 37) with swap_states_schema_version_37: self.save_new_question( self.QUESTION_ID, self.albert_id, self._create_valid_question_data('ABC'), [self.skill_id]) # Bring the main question to schema version 38. migration_change_list = [ question_domain.QuestionChange({ 'cmd': ( question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION ), 'from_version': '37', 'to_version': '38' }) ] swap_states_schema_version_38 = self.swap( feconf, 'CURRENT_STATE_SCHEMA_VERSION', 38) with swap_states_schema_version_38: question_services.update_question( self.albert_id, self.QUESTION_ID, migration_change_list, 'Ran Question Migration job.') job_id = ( question_jobs_one_off.QuestionSnapshotsMigrationJob. create_new()) question_jobs_one_off.QuestionSnapshotsMigrationJob.enqueue( job_id) self.process_and_flush_pending_mapreduce_tasks() actual_output = ( question_jobs_one_off.QuestionSnapshotsMigrationJob.get_output( job_id)) expected_output = [ '[u\'SUCCESS - Model saved\', 1]', '[u\'SUCCESS - Model upgraded\', 1]', '[u\'SUCCESS - Snapshot is already at latest schema version\', 1]'] self.assertEqual(sorted(actual_output), sorted(expected_output))
def test_update_question(self): state = exp_domain.State.create_default_state('ABC') question_data = state.to_dict() question_id = 'dummy' title = 'A Question' question_data_schema_version = 1 collection_id = 'col1' language_code = 'en' question = question_domain.Question(question_id, title, question_data, question_data_schema_version, collection_id, language_code) question_id = question_services.add_question(self.owner_id, question) change_dict = { 'cmd': 'update_question_property', 'property_name': 'title', 'new_value': 'ABC', 'old_value': 'A Question' } change_list = [question_domain.QuestionChange(change_dict)] with self.assertRaisesRegexp( Exception, ('The question with ID %s is not present' ' in the given collection' % question_id)): question_services.update_question(self.owner_id, 'random', question_id, change_list, 'updated') question_services.update_question(self.owner_id, collection_id, question_id, change_list, ('updated title')) model = question_models.QuestionModel.get(question_id) self.assertEqual(model.title, 'ABC') self.assertEqual(model.question_data, question_data) self.assertEqual(model.question_data_schema_version, question_data_schema_version) self.assertEqual(model.collection_id, collection_id) self.assertEqual(model.language_code, language_code)
def put(self, question_id): """Updates properties of the given question.""" commit_message = self.payload.get('commit_message') if not commit_message: raise self.PageNotFoundException if not self.payload.get('change_list'): raise self.PageNotFoundException change_list = [ question_domain.QuestionChange(change) for change in self.payload.get('change_list') ] for change in change_list: if (change.cmd == question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION): raise self.InvalidInputException question_services.update_question(self.user_id, question_id, change_list, commit_message) question_dict = question_services.get_question_by_id( question_id).to_dict() self.render_json({'question_dict': question_dict})