Merge remote-tracking branch 'origin/release' into rc/2015-06-29
Conflicts: requirements/edx/github.txt
This commit is contained in:
@@ -154,7 +154,7 @@ class XBlockVisibilityTestCase(ModuleStoreTestCase):
|
||||
super(XBlockVisibilityTestCase, self).setUp()
|
||||
|
||||
self.dummy_user = ModuleStoreEnum.UserID.test
|
||||
self.past = datetime(1970, 1, 1)
|
||||
self.past = datetime(1970, 1, 1, tzinfo=UTC)
|
||||
self.future = datetime.now(UTC) + timedelta(days=1)
|
||||
self.course = CourseFactory.create()
|
||||
|
||||
|
||||
@@ -1875,6 +1875,11 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
||||
block_data.fields = settings
|
||||
|
||||
new_id = new_structure['_id']
|
||||
|
||||
# source_version records which revision a block was copied from. In this method, we're updating
|
||||
# the block, so it's no longer a direct copy, and we can remove the source_version reference.
|
||||
block_data.edit_info.source_version = None
|
||||
|
||||
self.version_block(block_data, user_id, new_id)
|
||||
self.update_structure(course_key, new_structure)
|
||||
# update the index entry if appropriate
|
||||
@@ -2969,8 +2974,11 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
||||
if getattr(destination_block.edit_info, key) is None:
|
||||
setattr(destination_block.edit_info, key, val)
|
||||
|
||||
# introduce new edit info field for tracing where copied/published blocks came
|
||||
destination_block.edit_info.source_version = new_block.edit_info.update_version
|
||||
# If the block we are copying from was itself a copy, then just
|
||||
# reference the original source, rather than the copy.
|
||||
destination_block.edit_info.source_version = (
|
||||
new_block.edit_info.source_version or new_block.edit_info.update_version
|
||||
)
|
||||
|
||||
if blacklist != EXCLUDE_ALL:
|
||||
for child in destination_block.fields.get('children', []):
|
||||
|
||||
@@ -523,6 +523,75 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
component = self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
def test_unit_stuck_in_draft_mode(self, default_ms):
|
||||
"""
|
||||
After revert_to_published() the has_changes() should return false if draft has no changes
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
|
||||
test_course = self.store.create_course('testx', 'GreekHero', 'test_run', self.user_id)
|
||||
|
||||
# Create a dummy component to test against
|
||||
xblock = self.store.create_item(
|
||||
self.user_id,
|
||||
test_course.id,
|
||||
'vertical',
|
||||
block_id='test_vertical'
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
component = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
self.store.revert_to_published(component.location, self.user_id)
|
||||
component = self.store.get_item(component.location)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
# Publish and verify again
|
||||
component = self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
def test_unit_stuck_in_published_mode(self, default_ms):
|
||||
"""
|
||||
After revert_to_published() the has_changes() should return true if draft has changes
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
|
||||
test_course = self.store.create_course('testx', 'GreekHero', 'test_run', self.user_id)
|
||||
|
||||
# Create a dummy component to test against
|
||||
xblock = self.store.create_item(
|
||||
self.user_id,
|
||||
test_course.id,
|
||||
'vertical',
|
||||
block_id='test_vertical'
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
component = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
# Discard changes and verify that there are no changes
|
||||
self.store.revert_to_published(component.location, self.user_id)
|
||||
component = self.store.get_item(component.location)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
# Change the component, then check that there now are changes
|
||||
component = self.store.get_item(component.location)
|
||||
component.display_name = 'Changed Display Name'
|
||||
self.store.update_item(component, self.user_id)
|
||||
|
||||
# Verify that changes are present
|
||||
self.assertTrue(self.store.has_changes(component))
|
||||
|
||||
def setup_has_changes(self, default_ms):
|
||||
"""
|
||||
Common set up for has_changes tests below.
|
||||
|
||||
@@ -1182,9 +1182,7 @@ def _update_module_location(module, new_location):
|
||||
# in which one component of the key is the XBlock's location (equivalent to "scope_ids").
|
||||
# Since we've changed the XBlock's location, we need to re-save
|
||||
# all the XBlock's fields so they will be stored using the new location in the key.
|
||||
# However, since XBlocks only save "dirty" fields, we need to first
|
||||
# explicitly set each field to its current value before triggering the save.
|
||||
# However, since XBlocks only save "dirty" fields, we need to call
|
||||
# XBlock's `force_save_fields_method`
|
||||
if len(rekey_fields) > 0:
|
||||
for rekey_field_name in rekey_fields:
|
||||
setattr(module, rekey_field_name, getattr(module, rekey_field_name))
|
||||
module.save()
|
||||
module.force_save_fields(rekey_fields)
|
||||
|
||||
@@ -188,9 +188,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 18, 36)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 18, 36, tzinfo=UTC)
|
||||
)
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
@@ -202,9 +202,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 35)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 35, tzinfo=UTC)
|
||||
)
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
@@ -216,9 +216,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 36)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 36, tzinfo=UTC)
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
@@ -230,9 +230,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC)
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
@@ -246,17 +246,17 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
with self.assertRaises(xmodule.exceptions.NotFoundError):
|
||||
(module, unused_result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC)
|
||||
)
|
||||
|
||||
# Now try it without the check_problem
|
||||
(module, unused_result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0),
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC),
|
||||
skip_check_problem=True
|
||||
)
|
||||
# Expect that number of attempts NOT incremented
|
||||
@@ -267,9 +267,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60 * 60 * 2,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 2, 15, 35)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 2, 15, 35, tzinfo=UTC)
|
||||
)
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
@@ -281,9 +281,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60 * 60 * 2 + 63,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 1, 15, 40)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 1, 15, 40, tzinfo=UTC)
|
||||
)
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
@@ -295,9 +295,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36),
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60,
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 17, 36)
|
||||
considered_now=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC)
|
||||
)
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
|
||||
@@ -381,9 +381,10 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
|
||||
if not self.fields['download_video'].is_set_on(self):
|
||||
self.download_video = True
|
||||
|
||||
# Set download_video field to default value if its not explicitly set for backward compatibility.
|
||||
# Force download_video field to default value if it's not explicitly set for backward compatibility.
|
||||
if not self.fields['download_video'].is_set_on(self):
|
||||
self.download_video = self.download_video
|
||||
self.force_save_fields(['download_video'])
|
||||
|
||||
# for backward compatibility.
|
||||
# If course was existed and was not re-imported by the moment of adding `download_track` field,
|
||||
|
||||
@@ -18,7 +18,7 @@ from capa.tests.response_xml_factory import (
|
||||
CodeResponseXMLFactory,
|
||||
)
|
||||
from courseware import grades
|
||||
from courseware.models import StudentModule
|
||||
from courseware.models import StudentModule, StudentModuleHistory
|
||||
from courseware.tests.helpers import LoginEnrollmentTestCase
|
||||
from lms.djangoapps.lms_xblock.runtime import quote_slashes
|
||||
from student.tests.factories import UserFactory
|
||||
@@ -426,6 +426,32 @@ class TestCourseGrader(TestSubmittingProblems):
|
||||
)
|
||||
self.assertEqual(json.loads(resp.content).get("success"), err_msg)
|
||||
|
||||
def test_show_answer_doesnt_write_to_csm(self):
|
||||
self.basic_setup()
|
||||
self.submit_question_answer('p1', {'2_1': u'Correct'})
|
||||
|
||||
# Now fetch the state entry for that problem.
|
||||
student_module = StudentModule.objects.get(
|
||||
course_id=self.course.id,
|
||||
student=self.student_user
|
||||
)
|
||||
# count how many state history entries there are
|
||||
baseline = StudentModuleHistory.objects.filter(
|
||||
student_module=student_module
|
||||
)
|
||||
baseline_count = baseline.count()
|
||||
self.assertEqual(baseline_count, 3)
|
||||
|
||||
# now click "show answer"
|
||||
self.show_question_answer('p1')
|
||||
|
||||
# check that we don't have more state history entries
|
||||
csmh = StudentModuleHistory.objects.filter(
|
||||
student_module=student_module
|
||||
)
|
||||
current_count = csmh.count()
|
||||
self.assertEqual(current_count, 3)
|
||||
|
||||
def test_none_grade(self):
|
||||
"""
|
||||
Check grade is 0 to begin with.
|
||||
|
||||
@@ -32,7 +32,7 @@ git+https://github.com/hmarr/django-debug-toolbar-mongo.git@b0686a76f1ce3532088c
|
||||
-e git+https://github.com/jazkarta/ccx-keys.git@e6b03704b1bb97c1d2f31301ecb4e3a687c536ea#egg=ccx-keys
|
||||
|
||||
# Our libraries:
|
||||
-e git+https://github.com/edx/XBlock.git@74fdc5a361f48e5596acf3846ca3790a33a05253#egg=XBlock
|
||||
-e git+https://github.com/edx/XBlock.git@017b46b80e712b1318379912257cf1cc1b68eb0e#egg=XBlock
|
||||
-e git+https://github.com/edx/codejail.git@6b17c33a89bef0ac510926b1d7fea2748b73aadd#egg=codejail
|
||||
-e git+https://github.com/edx/js-test-tool.git@v0.1.6#egg=js_test_tool
|
||||
-e git+https://github.com/edx/event-tracking.git@0.2.0#egg=event-tracking
|
||||
|
||||
Reference in New Issue
Block a user