Commit 9209eef7 by Sanford Student

add grading policy hash to transformer

parent 2ca7484c
......@@ -7,9 +7,11 @@ import pytz
import random
import ddt
from copy import deepcopy
from student.tests.factories import UserFactory
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import check_mongo_calls
......@@ -39,6 +41,27 @@ class GradesTransformerTestCase(CourseStructureTestCase):
self.student = UserFactory.create(is_staff=False, username=u'test_student', password=password)
self.client.login(username=self.student.username, password=password)
def _update_course_grading_policy(self, course, grading_policy):
"""
Helper to update a course's grading policy in the modulestore.
"""
course.set_grading_policy(grading_policy)
modulestore().update_item(course, self.user.id)
def _validate_grading_policy_hash(self, course_location, grading_policy_hash):
"""
Helper to retrieve the course at the given course_location and
assert that its hashed grading policy (from the grades transformer)
is as expected.
"""
block_structure = get_course_blocks(self.student, course_location, self.transformers)
self.assert_collected_transformer_block_fields(
block_structure,
course_location,
self.TRANSFORMER_CLASS_TO_TEST,
grading_policy_hash=grading_policy_hash,
)
def assert_collected_xblock_fields(self, block_structure, usage_key, **expectations):
"""
Given a block structure, a block usage key, and a list of keyword
......@@ -330,6 +353,38 @@ class GradesTransformerTestCase(CourseStructureTestCase):
block_structure = get_course_blocks(self.student, blocks[u'course'].location, self.transformers)
self.assertIsNotNone(block_structure.get_xblock_field(blocks[u'course'].location, u'course_version'))
def test_grading_policy_collected(self):
# the calculated hash of the original and updated grading policies of the test course
original_grading_policy_hash = u'ChVp0lHGQGCevD0t4njna/C44zQ='
updated_grading_policy_hash = u'TsbX04qWOy1WRnC0NHy+94upPd4='
blocks = self.build_course_with_problems()
course_block = blocks[u'course']
self._validate_grading_policy_hash(
course_block.location,
original_grading_policy_hash
)
# make sure the hash changes when the course grading policy is edited
grading_policy_with_updates = course_block.grading_policy
original_grading_policy = deepcopy(grading_policy_with_updates)
for section in grading_policy_with_updates['GRADER']:
self.assertNotEqual(section['weight'], 0.25)
section['weight'] = 0.25
self._update_course_grading_policy(course_block, grading_policy_with_updates)
self._validate_grading_policy_hash(
course_block.location,
updated_grading_policy_hash
)
# reset the grading policy and ensure the hash matches the original
self._update_course_grading_policy(course_block, original_grading_policy)
self._validate_grading_policy_hash(
course_block.location,
original_grading_policy_hash
)
class MultiProblemModulestoreAccessTestCase(CourseStructureTestCase, SharedModuleStoreTestCase):
"""
......
"""
Grades Transformer
"""
from base64 import b64encode
from django.test.client import RequestFactory
from functools import reduce as functools_reduce
from hashlib import sha1
from logging import getLogger
import json
from courseware.model_data import FieldDataCache
from courseware.module_render import get_module_for_descriptor
......@@ -64,6 +67,7 @@ class GradesTransformer(BlockStructureTransformer):
filter_by=lambda block_key: block_key.block_type == 'sequential',
)
cls._collect_explicit_graded(block_structure)
cls._collect_grading_policy_hash(block_structure)
def transform(self, block_structure, usage_context):
"""
......@@ -128,6 +132,35 @@ class GradesTransformer(BlockStructureTransformer):
if max_score is None:
log.warning("GradesTransformer: max_score is None for {}".format(module.location))
@classmethod
def _collect_grading_policy_hash(cls, block_structure):
"""
Collect a hash of the course's grading policy, storing it as a
`transformer_block_field` associated with the `GradesTransformer`.
"""
def _hash_grading_policy(policy):
"""
Creates a hash from the course grading policy.
The keys are sorted in order to make the hash
agnostic to the ordering of the policy coming in.
"""
ordered_policy = json.dumps(
policy,
separators=(',', ':'), # Remove spaces from separators for more compact representation
sort_keys=True,
)
return b64encode(sha1(ordered_policy).digest())
course_location = block_structure.root_block_usage_key
course_block = block_structure.get_xblock(course_location)
grading_policy = course_block.grading_policy
block_structure.set_transformer_block_field(
course_block.location,
cls,
"grading_policy_hash",
_hash_grading_policy(grading_policy)
)
@staticmethod
def _iter_scorable_xmodules(block_structure):
"""
......
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