diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/tests/__init__.py b/cms/djangoapps/contentstore/xblock_storage_handlers/tests/__init__.py new file mode 100644 index 000000000000..1050069eeffd --- /dev/null +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/tests/__init__.py @@ -0,0 +1,3 @@ +""" +Tests for xblock_storage_handlers +""" diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/tests/test_problem_weight_fix.py b/cms/djangoapps/contentstore/xblock_storage_handlers/tests/test_problem_weight_fix.py new file mode 100644 index 000000000000..0b1ad6a7beb4 --- /dev/null +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/tests/test_problem_weight_fix.py @@ -0,0 +1,102 @@ +"""Tests for problem weight metadata fix.""" +from unittest.mock import Mock +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory +from xmodule.modulestore.inheritance import own_metadata +from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import get_block_info + + +class ProblemWeightMetadataTestCase(ModuleStoreTestCase): + """Test problem weight population from max_score.""" + + def setUp(self): + super().setUp() + self.course = CourseFactory.create() + + def test_weight_from_max_score(self): + """Weight should be populated from max_score when not explicitly set.""" + problem_xml = """ + + + + A + + + + + B + + + + + C + + + + """ + + problem = BlockFactory.create( + parent_location=self.course.location, + category="problem", + data=problem_xml + ) + + self.assertNotIn('weight', own_metadata(problem)) + self.assertEqual(problem.max_score(), 3.0) + + block_info = get_block_info(problem) + + self.assertEqual(block_info['metadata']['weight'], 3.0) + + def test_explicit_weight_preserved(self): + """Explicit weight should not be overridden.""" + problem = BlockFactory.create( + parent_location=self.course.location, + category="problem", + data="A", + weight=5.0 + ) + + block_info = get_block_info(problem) + + self.assertEqual(block_info['metadata']['weight'], 5.0) + + def test_zero_max_score(self): + """Weight should not be set for zero max_score.""" + problem = BlockFactory.create( + parent_location=self.course.location, + category="problem", + data="

No questions

" + ) + + self.assertEqual(problem.max_score(), 0) + + block_info = get_block_info(problem) + + self.assertNotIn('weight', block_info['metadata']) + + def test_non_problem_unaffected(self): + """Non-problem blocks should not have weight added.""" + html_block = BlockFactory.create( + parent_location=self.course.location, + category="html", + data="

Content

" + ) + + block_info = get_block_info(html_block) + + self.assertNotIn('weight', block_info['metadata']) + + def test_max_score_exception_handled(self): + """Exceptions from max_score should be handled gracefully.""" + problem = BlockFactory.create( + parent_location=self.course.location, + category="problem", + data="A" + ) + + problem.max_score = Mock(side_effect=Exception("Test")) + + block_info = get_block_info(problem) + + self.assertIn('metadata', block_info) diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py index f7c96d588a2e..184670fd8e6c 100644 --- a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py @@ -974,11 +974,21 @@ def get_block_info( modulestore().get_course(xblock.location.course_key, depth=None) ) + metadata = own_metadata(xblock) + + if xblock.scope_ids.block_type == 'problem' and 'weight' not in metadata: + try: + max_score_value = xblock.max_score() + if max_score_value and max_score_value > 0: + metadata['weight'] = float(max_score_value) + except Exception: # pylint: disable=broad-except + pass + # Note that children aren't being returned until we have a use case. xblock_info = create_xblock_info( xblock, data=data, - metadata=own_metadata(xblock), + metadata=metadata, include_ancestor_info=include_ancestor_info, include_children_predicate=include_children_predicate )