Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
31409940
Commit
31409940
authored
Sep 12, 2016
by
Nimisha Asthagiri
Committed by
GitHub
Sep 12, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #13433 from edx/tnl/enable-persistent-grades-in-tests
Enable Persistent Grades in unit tests
parents
a5376cd4
805bf287
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
136 additions
and
98 deletions
+136
-98
lms/djangoapps/ccx/tests/test_field_override_performance.py
+1
-0
lms/djangoapps/courseware/tests/test_submitting_problems.py
+31
-11
lms/djangoapps/courseware/tests/test_views.py
+2
-0
lms/djangoapps/grades/config/models.py
+3
-0
lms/djangoapps/grades/config/tests/test_models.py
+9
-10
lms/djangoapps/grades/models.py
+23
-20
lms/djangoapps/grades/signals/handlers.py
+0
-4
lms/djangoapps/grades/tests/test_models.py
+30
-20
lms/djangoapps/grades/tests/test_new.py
+30
-33
lms/djangoapps/grades/tests/test_signals.py
+2
-0
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
+2
-0
lms/envs/test.py
+3
-0
No files found.
lms/djangoapps/ccx/tests/test_field_override_performance.py
View file @
31409940
...
@@ -36,6 +36,7 @@ from openedx.core.djangoapps.content.block_structure.api import get_course_in_ca
...
@@ -36,6 +36,7 @@ from openedx.core.djangoapps.content.block_structure.api import get_course_in_ca
'django.conf.settings.FEATURES'
,
'django.conf.settings.FEATURES'
,
{
{
'ENABLE_XBLOCK_VIEW_ENDPOINT'
:
True
,
'ENABLE_XBLOCK_VIEW_ENDPOINT'
:
True
,
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
# disable persistent grades until TNL-5458 (reduces queries)
}
}
)
)
@ddt.ddt
@ddt.ddt
...
...
lms/djangoapps/courseware/tests/test_submitting_problems.py
View file @
31409940
...
@@ -25,6 +25,7 @@ from courseware.models import StudentModule, BaseStudentModuleHistory
...
@@ -25,6 +25,7 @@ from courseware.models import StudentModule, BaseStudentModuleHistory
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
lms.djangoapps.lms_xblock.runtime
import
quote_slashes
from
lms.djangoapps.lms_xblock.runtime
import
quote_slashes
from
student.models
import
anonymous_id_for_user
,
CourseEnrollment
from
student.models
import
anonymous_id_for_user
,
CourseEnrollment
from
submissions
import
api
as
submissions_api
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.partitions.partitions
import
Group
,
UserPartition
from
xmodule.partitions.partitions
import
Group
,
UserPartition
...
@@ -143,9 +144,22 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
...
@@ -143,9 +144,22 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
self
.
student_user
=
User
.
objects
.
get
(
email
=
self
.
student
)
self
.
student_user
=
User
.
objects
.
get
(
email
=
self
.
student
)
self
.
factory
=
RequestFactory
()
self
.
factory
=
RequestFactory
()
# Disable the score change signal to prevent other components from being pulled into tests.
# Disable the score change signal to prevent other components from being pulled into tests.
signal_patch
=
patch
(
'courseware.module_render.SCORE_CHANGED.send'
)
self
.
score_changed_signal_patch
=
patch
(
'courseware.module_render.SCORE_CHANGED.send'
)
signal_patch
.
start
()
self
.
score_changed_signal_patch
.
start
()
self
.
addCleanup
(
signal_patch
.
stop
)
def
tearDown
(
self
):
super
(
TestSubmittingProblems
,
self
)
.
tearDown
()
self
.
_stop_signal_patch
()
def
_stop_signal_patch
(
self
):
"""
Stops the signal patch for the SCORE_CHANGED event.
In case a test wants to test with the event actually
firing.
"""
if
self
.
score_changed_signal_patch
:
self
.
score_changed_signal_patch
.
stop
()
self
.
score_changed_signal_patch
=
None
def
add_dropdown_to_section
(
self
,
section_location
,
name
,
num_inputs
=
2
):
def
add_dropdown_to_section
(
self
,
section_location
,
name
,
num_inputs
=
2
):
"""
"""
...
@@ -540,14 +554,20 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -540,14 +554,20 @@ class TestCourseGrader(TestSubmittingProblems):
self
.
check_grade_percent
(
0.67
)
self
.
check_grade_percent
(
0.67
)
self
.
assertEqual
(
self
.
get_grade_summary
()[
'grade'
],
'B'
)
self
.
assertEqual
(
self
.
get_grade_summary
()[
'grade'
],
'B'
)
# But now we mock out a get_scores call, and watch as it overrides the
# But now, set the score with the submissions API and watch
# score read from StudentModule and our student gets an A instead.
# as it overrides the score read from StudentModule and our
with
patch
(
'submissions.api.get_scores'
)
as
mock_get_scores
:
# student gets an A instead.
mock_get_scores
.
return_value
=
{
self
.
_stop_signal_patch
()
self
.
problem_location
(
'p3'
)
.
to_deprecated_string
():
(
1
,
1
)
student_item
=
{
}
'student_id'
:
anonymous_id_for_user
(
self
.
student_user
,
self
.
course
.
id
),
self
.
check_grade_percent
(
1.0
)
'course_id'
:
unicode
(
self
.
course
.
id
),
self
.
assertEqual
(
self
.
get_grade_summary
()[
'grade'
],
'A'
)
'item_id'
:
unicode
(
self
.
problem_location
(
'p3'
)),
'item_type'
:
'problem'
}
submission
=
submissions_api
.
create_submission
(
student_item
,
'any answer'
)
submissions_api
.
set_score
(
submission
[
'uuid'
],
1
,
1
)
self
.
check_grade_percent
(
1.0
)
self
.
assertEqual
(
self
.
get_grade_summary
()[
'grade'
],
'A'
)
def
test_submissions_api_anonymous_student_id
(
self
):
def
test_submissions_api_anonymous_student_id
(
self
):
"""
"""
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
31409940
...
@@ -1345,6 +1345,8 @@ class ProgressPageTests(ModuleStoreTestCase):
...
@@ -1345,6 +1345,8 @@ class ProgressPageTests(ModuleStoreTestCase):
)
)
self
.
assertContains
(
resp
,
u"Download Your Certificate"
)
self
.
assertContains
(
resp
,
u"Download Your Certificate"
)
# disable persistent grades until TNL-5458 (reduces query counts)
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
@ddt.data
(
*
itertools
.
product
(((
39
,
4
,
True
),
(
39
,
4
,
False
)),
(
True
,
False
))
*
itertools
.
product
(((
39
,
4
,
True
),
(
39
,
4
,
False
)),
(
True
,
False
))
)
)
...
...
lms/djangoapps/grades/config/models.py
View file @
31409940
...
@@ -3,6 +3,7 @@ Models for configuration of the feature flags
...
@@ -3,6 +3,7 @@ Models for configuration of the feature flags
controlling persistent grades.
controlling persistent grades.
"""
"""
from
config_models.models
import
ConfigurationModel
from
config_models.models
import
ConfigurationModel
from
django.conf
import
settings
from
django.db.models
import
BooleanField
from
django.db.models
import
BooleanField
from
xmodule_django.models
import
CourseKeyField
from
xmodule_django.models
import
CourseKeyField
...
@@ -29,6 +30,8 @@ class PersistentGradesEnabledFlag(ConfigurationModel):
...
@@ -29,6 +30,8 @@ class PersistentGradesEnabledFlag(ConfigurationModel):
If the flag is enabled and no course ID is given,
If the flag is enabled and no course ID is given,
we return True since the global setting is enabled.
we return True since the global setting is enabled.
"""
"""
if
settings
.
FEATURES
.
get
(
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
):
return
True
if
not
PersistentGradesEnabledFlag
.
is_enabled
():
if
not
PersistentGradesEnabledFlag
.
is_enabled
():
return
False
return
False
elif
not
PersistentGradesEnabledFlag
.
current
()
.
enabled_for_all_courses
and
course_id
:
elif
not
PersistentGradesEnabledFlag
.
current
()
.
enabled_for_all_courses
and
course_id
:
...
...
lms/djangoapps/grades/config/tests/test_models.py
View file @
31409940
...
@@ -3,6 +3,9 @@ Tests for the models that control the
...
@@ -3,6 +3,9 @@ Tests for the models that control the
persistent grading feature.
persistent grading feature.
"""
"""
import
ddt
import
ddt
from
django.conf
import
settings
import
itertools
from
mock
import
patch
from
django.test
import
TestCase
from
django.test
import
TestCase
from
opaque_keys.edx.locator
import
CourseLocator
from
opaque_keys.edx.locator
import
CourseLocator
...
@@ -10,6 +13,7 @@ from lms.djangoapps.grades.config.models import PersistentGradesEnabledFlag
...
@@ -10,6 +13,7 @@ from lms.djangoapps.grades.config.models import PersistentGradesEnabledFlag
from
lms.djangoapps.grades.config.tests.utils
import
persistent_grades_feature_flags
from
lms.djangoapps.grades.config.tests.utils
import
persistent_grades_feature_flags
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.ddt
@ddt.ddt
class
PersistentGradesFeatureFlagTests
(
TestCase
):
class
PersistentGradesFeatureFlagTests
(
TestCase
):
"""
"""
...
@@ -21,16 +25,11 @@ class PersistentGradesFeatureFlagTests(TestCase):
...
@@ -21,16 +25,11 @@ class PersistentGradesFeatureFlagTests(TestCase):
self
.
course_id_1
=
CourseLocator
(
org
=
"edx"
,
course
=
"course"
,
run
=
"run"
)
self
.
course_id_1
=
CourseLocator
(
org
=
"edx"
,
course
=
"course"
,
run
=
"run"
)
self
.
course_id_2
=
CourseLocator
(
org
=
"edx"
,
course
=
"course2"
,
run
=
"run"
)
self
.
course_id_2
=
CourseLocator
(
org
=
"edx"
,
course
=
"course2"
,
run
=
"run"
)
@ddt.data
(
@ddt.data
(
*
itertools
.
product
(
(
True
,
True
,
True
),
(
True
,
False
),
(
True
,
True
,
False
),
(
True
,
False
),
(
True
,
False
,
True
),
(
True
,
False
),
(
True
,
False
,
False
),
))
(
False
,
True
,
True
),
(
False
,
False
,
True
),
(
False
,
True
,
False
),
(
False
,
False
,
False
),
)
@ddt.unpack
@ddt.unpack
def
test_persistent_grades_feature_flags
(
self
,
global_flag
,
enabled_for_all_courses
,
enabled_for_course_1
):
def
test_persistent_grades_feature_flags
(
self
,
global_flag
,
enabled_for_all_courses
,
enabled_for_course_1
):
with
persistent_grades_feature_flags
(
with
persistent_grades_feature_flags
(
...
...
lms/djangoapps/grades/models.py
View file @
31409940
...
@@ -29,13 +29,16 @@ log = logging.getLogger(__name__)
...
@@ -29,13 +29,16 @@ log = logging.getLogger(__name__)
BlockRecord
=
namedtuple
(
'BlockRecord'
,
[
'locator'
,
'weight'
,
'max_score'
])
BlockRecord
=
namedtuple
(
'BlockRecord'
,
[
'locator'
,
'weight'
,
'max_score'
])
class
BlockRecord
Set
(
frozenset
):
class
BlockRecord
List
(
tuple
):
"""
"""
An immutable ordered
collection
of BlockRecord objects.
An immutable ordered
list
of BlockRecord objects.
"""
"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__new__
(
cls
,
blocks
):
super
(
BlockRecordSet
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
return
super
(
BlockRecordList
,
cls
)
.
__new__
(
cls
,
tuple
(
blocks
))
def
__init__
(
self
,
blocks
):
super
(
BlockRecordList
,
self
)
.
__init__
(
blocks
)
self
.
_json
=
None
self
.
_json
=
None
self
.
_hash
=
None
self
.
_hash
=
None
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
stable ordering.
stable ordering.
"""
"""
if
self
.
_json
is
None
:
if
self
.
_json
is
None
:
sorted_blocks
=
sorted
(
self
,
key
=
attrgetter
(
'locator'
))
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
self
]
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
sorted_blocks
]
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
for
block_dict
in
list_of_block_dicts
:
for
block_dict
in
list_of_block_dicts
:
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
@classmethod
@classmethod
def
from_json
(
cls
,
blockrecord_json
):
def
from_json
(
cls
,
blockrecord_json
):
"""
"""
Return a BlockRecord
Set from a json list
.
Return a BlockRecord
List from a previously serialized json
.
"""
"""
data
=
json
.
loads
(
blockrecord_json
)
data
=
json
.
loads
(
blockrecord_json
)
course_key
=
data
[
'course_key'
]
course_key
=
data
[
'course_key'
]
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
)
)
return
cls
(
record_generator
)
return
cls
(
record_generator
)
@classmethod
def
from_list
(
cls
,
blocks
):
"""
Return a BlockRecordList from a list.
"""
return
cls
(
tuple
(
blocks
))
def
to_hash
(
self
):
def
to_hash
(
self
):
"""
"""
Return a hashed version of the list of block records.
Return a hashed version of the list of block records.
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
"""
"""
Creates a new VisibleBlocks model object.
Creates a new VisibleBlocks model object.
Argument 'blocks' should be a BlockRecord
Se
t.
Argument 'blocks' should be a BlockRecord
Lis
t.
"""
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
model
,
_
=
self
.
get_or_create
(
hashed
=
blocks
.
to_hash
(),
defaults
=
{
'blocks_json'
:
blocks
.
to_json
()})
model
,
_
=
self
.
get_or_create
(
hashed
=
blocks
.
to_hash
(),
defaults
=
{
'blocks_json'
:
blocks
.
to_json
()})
return
model
return
model
def
hash_from_blockrecords
(
self
,
blocks
):
def
hash_from_blockrecords
(
self
,
blocks
):
"""
"""
Return the hash for a given
BlockRecordSet, serializ
ing the records if
Return the hash for a given
list of blocks, sav
ing the records if
possible, but returning the hash even if an IntegrityError occurs.
possible, but returning the hash even if an IntegrityError occurs.
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
Argument 'blocks' should be a BlockRecordList.
"""
try
:
try
:
with
transaction
.
atomic
():
with
transaction
.
atomic
():
model
=
self
.
create_from_blockrecords
(
blocks
)
model
=
self
.
create_from_blockrecords
(
blocks
)
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
Returns the blocks_json data stored on this model as a list of
Returns the blocks_json data stored on this model as a list of
BlockRecords in the order they were provided.
BlockRecords in the order they were provided.
"""
"""
return
BlockRecord
Se
t
.
from_json
(
self
.
blocks_json
)
return
BlockRecord
Lis
t
.
from_json
(
self
.
blocks_json
)
class
PersistentSubsectionGradeQuerySet
(
models
.
QuerySet
):
class
PersistentSubsectionGradeQuerySet
(
models
.
QuerySet
):
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
if
not
kwargs
.
get
(
'course_id'
,
None
):
if
not
kwargs
.
get
(
'course_id'
,
None
):
kwargs
[
'course_id'
]
=
kwargs
[
'usage_key'
]
.
course_key
kwargs
[
'course_id'
]
=
kwargs
[
'usage_key'
]
.
course_key
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
blocks
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
BlockRecordList
.
from_list
(
visible_blocks
)
)
return
super
(
PersistentSubsectionGradeQuerySet
,
self
)
.
create
(
return
super
(
PersistentSubsectionGradeQuerySet
,
self
)
.
create
(
visible_blocks_id
=
visible_blocks_hash
,
visible_blocks_id
=
visible_blocks_hash
,
**
kwargs
**
kwargs
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
Modify an existing PersistentSubsectionGrade object, saving the new
Modify an existing PersistentSubsectionGrade object, saving the new
version.
version.
"""
"""
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
blocks
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
BlockRecordList
.
from_list
(
visible_blocks
)
)
self
.
course_version
=
course_version
or
""
self
.
course_version
=
course_version
or
""
self
.
subtree_edited_timestamp
=
subtree_edited_timestamp
self
.
subtree_edited_timestamp
=
subtree_edited_timestamp
...
...
lms/djangoapps/grades/signals/handlers.py
View file @
31409940
...
@@ -43,8 +43,6 @@ def submissions_score_set_handler(sender, **kwargs): # pylint: disable=unused-a
...
@@ -43,8 +43,6 @@ def submissions_score_set_handler(sender, **kwargs): # pylint: disable=unused-a
usage_id
=
kwargs
[
'item_id'
]
usage_id
=
kwargs
[
'item_id'
]
user
=
user_by_anonymous_id
(
kwargs
[
'anonymous_user_id'
])
user
=
user_by_anonymous_id
(
kwargs
[
'anonymous_user_id'
])
# If any of the kwargs were missing, at least one of the following values
# will be None.
SCORE_CHANGED
.
send
(
SCORE_CHANGED
.
send
(
sender
=
None
,
sender
=
None
,
points_possible
=
points_possible
,
points_possible
=
points_possible
,
...
@@ -73,8 +71,6 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
...
@@ -73,8 +71,6 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
usage_id
=
kwargs
[
'item_id'
]
usage_id
=
kwargs
[
'item_id'
]
user
=
user_by_anonymous_id
(
kwargs
[
'anonymous_user_id'
])
user
=
user_by_anonymous_id
(
kwargs
[
'anonymous_user_id'
])
# If any of the kwargs were missing, at least one of the following values
# will be None.
SCORE_CHANGED
.
send
(
SCORE_CHANGED
.
send
(
sender
=
None
,
sender
=
None
,
points_possible
=
0
,
points_possible
=
0
,
...
...
lms/djangoapps/grades/tests/test_models.py
View file @
31409940
...
@@ -14,27 +14,27 @@ from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator
...
@@ -14,27 +14,27 @@ from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator
from
lms.djangoapps.grades.models
import
(
from
lms.djangoapps.grades.models
import
(
BlockRecord
,
BlockRecord
,
BlockRecord
Se
t
,
BlockRecord
Lis
t
,
PersistentSubsectionGrade
,
PersistentSubsectionGrade
,
VisibleBlocks
VisibleBlocks
)
)
class
BlockRecord
Se
tTestCase
(
TestCase
):
class
BlockRecord
Lis
tTestCase
(
TestCase
):
"""
"""
Verify the behavior of BlockRecord
Sets
, particularly around edge cases
Verify the behavior of BlockRecord
List
, particularly around edge cases
"""
"""
empty_json
=
'{"blocks":[],"course_key":null}'
empty_json
=
'{"blocks":[],"course_key":null}'
def
test_empty_block_record_set
(
self
):
def
test_empty_block_record_set
(
self
):
brs
=
BlockRecord
Set
(
)
brs
=
BlockRecord
List
(()
)
self
.
assertFalse
(
brs
)
self
.
assertFalse
(
brs
)
self
.
assertEqual
(
self
.
assertEqual
(
brs
.
to_json
(),
brs
.
to_json
(),
self
.
empty_json
self
.
empty_json
)
)
self
.
assertEqual
(
self
.
assertEqual
(
BlockRecord
Se
t
.
from_json
(
self
.
empty_json
),
BlockRecord
Lis
t
.
from_json
(
self
.
empty_json
),
brs
brs
)
)
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
"""
"""
Test the VisibleBlocks model.
Test the VisibleBlocks model.
"""
"""
def
_create_block_record_list
(
self
,
blocks
):
"""
Creates and returns a BlockRecordList for the given blocks.
"""
return
VisibleBlocks
.
objects
.
create_from_blockrecords
(
BlockRecordList
.
from_list
(
blocks
))
def
test_creation
(
self
):
def
test_creation
(
self
):
"""
"""
Happy path test to ensure basic create functionality works as expected.
Happy path test to ensure basic create functionality works as expected.
"""
"""
vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
])
vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
])
list_of_block_dicts
=
[
self
.
record_a
.
_asdict
()]
list_of_block_dicts
=
[
self
.
record_a
.
_asdict
()]
for
block_dict
in
list_of_block_dicts
:
for
block_dict
in
list_of_block_dicts
:
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
self
.
assertEqual
(
expected_hash
,
vblocks
.
hashed
)
self
.
assertEqual
(
expected_hash
,
vblocks
.
hashed
)
def
test_ordering_
does_not_matter
(
self
):
def
test_ordering_
matters
(
self
):
"""
"""
When creating new vblocks,
a different ordering of blocks produces the
When creating new vblocks,
different ordering of blocks produces
same record
in the database.
different records
in the database.
"""
"""
stored_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
,
self
.
record_b
])
stored_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
,
self
.
record_a
])
repeat_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
,
self
.
record_a
])
new_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
])
same_order_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
new_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
])
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
repeat_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
repeat_vblocks
.
hashed
)
self
.
assertEqual
(
stored_vblocks
.
pk
,
repeat
_vblocks
.
pk
)
self
.
assertEqual
s
(
stored_vblocks
.
pk
,
same_order
_vblocks
.
pk
)
self
.
assertEqual
(
stored_vblocks
.
hashed
,
repeat
_vblocks
.
hashed
)
self
.
assertEqual
s
(
stored_vblocks
.
hashed
,
same_order
_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
def
test_blocks_property
(
self
):
def
test_blocks_property
(
self
):
"""
"""
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing
Ensures that, given an array of BlockRecord, creating visible_blocks
visible_blocks.blocks yields a copy of the initial array. Also, trying to set the blocks property should raise
and accessing visible_blocks.blocks yields a copy of the initial array.
an exception.
Also, trying to set the blocks property should raise
an exception.
"""
"""
expected_blocks
=
[
self
.
record_a
,
self
.
record_b
]
expected_blocks
=
(
self
.
record_a
,
self
.
record_b
)
visible_blocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
(
expected_blocks
)
visible_blocks
=
self
.
_create_block_record_list
(
expected_blocks
)
self
.
assertEqual
(
BlockRecordSet
(
expected_blocks
)
,
visible_blocks
.
blocks
)
self
.
assertEqual
(
expected_blocks
,
visible_blocks
.
blocks
)
with
self
.
assertRaises
(
AttributeError
):
with
self
.
assertRaises
(
AttributeError
):
visible_blocks
.
blocks
=
expected_blocks
visible_blocks
.
blocks
=
expected_blocks
...
...
lms/djangoapps/grades/tests/test_new.py
View file @
31409940
...
@@ -3,6 +3,7 @@ Test saved subsection grade functionality.
...
@@ -3,6 +3,7 @@ Test saved subsection grade functionality.
"""
"""
import
ddt
import
ddt
from
django.conf
import
settings
from
mock
import
patch
from
mock
import
patch
from
capa.tests.response_xml_factory
import
MultipleChoiceResponseXMLFactory
from
capa.tests.response_xml_factory
import
MultipleChoiceResponseXMLFactory
...
@@ -71,6 +72,7 @@ class TestCourseGradeFactory(GradeTestBase):
...
@@ -71,6 +72,7 @@ class TestCourseGradeFactory(GradeTestBase):
Test that CourseGrades are calculated properly
Test that CourseGrades are calculated properly
"""
"""
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
@ddt.data
(
(
True
,
True
),
(
True
,
True
),
(
True
,
False
),
(
True
,
False
),
...
@@ -107,44 +109,39 @@ class SubsectionGradeFactoryTest(GradeTestBase):
...
@@ -107,44 +109,39 @@ class SubsectionGradeFactoryTest(GradeTestBase):
"""
"""
Tests to ensure that a persistent subsection grade is created, saved, then fetched on re-request.
Tests to ensure that a persistent subsection grade is created, saved, then fetched on re-request.
"""
"""
with
persistent_grades_feature_flags
(
with
patch
(
global_flag
=
True
,
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._save_grade'
,
enabled_for_all_courses
=
False
,
wraps
=
self
.
subsection_grade_factory
.
_save_grade
# pylint: disable=protected-access
course_id
=
self
.
course
.
id
,
)
as
mock_save_grades
:
enabled_for_course
=
True
):
with
patch
(
with
patch
(
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._save_grade'
,
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._get_saved_grade'
,
wraps
=
self
.
subsection_grade_factory
.
_save_grade
# pylint: disable=protected-access
wraps
=
self
.
subsection_grade_factory
.
_get_saved_grade
# pylint: disable=protected-access
)
as
mock_save_grades
:
)
as
mock_get_saved_grade
:
with
patch
(
with
self
.
assertNumQueries
(
19
):
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._get_saved_grade'
,
grade_a
=
self
.
subsection_grade_factory
.
create
(
wraps
=
self
.
subsection_grade_factory
.
_get_saved_grade
# pylint: disable=protected-access
self
.
sequence
,
)
as
mock_get_saved_grade
:
self
.
course_structure
,
with
self
.
assertNumQueries
(
22
):
self
.
course
grade_a
=
self
.
subsection_grade_factory
.
create
(
)
self
.
sequence
,
self
.
assertTrue
(
mock_get_saved_grade
.
called
)
self
.
course_structure
,
self
.
assertTrue
(
mock_save_grades
.
called
)
self
.
course
)
mock_get_saved_grade
.
reset_mock
()
self
.
assertTrue
(
mock_get_saved_grade
.
called
)
mock_save_grades
.
reset_mock
()
self
.
assertTrue
(
mock_save_grades
.
called
)
with
self
.
assertNumQueries
(
3
):
mock_get_saved_grade
.
reset_mock
()
grade_b
=
self
.
subsection_grade_factory
.
create
(
mock_save_grades
.
reset_mock
()
self
.
sequence
,
self
.
course_structure
,
with
self
.
assertNumQueries
(
4
):
self
.
course
grade_b
=
self
.
subsection_grade_factory
.
create
(
)
self
.
sequence
,
self
.
assertTrue
(
mock_get_saved_grade
.
called
)
self
.
course_structure
,
self
.
assertFalse
(
mock_save_grades
.
called
)
self
.
course
)
self
.
assertTrue
(
mock_get_saved_grade
.
called
)
self
.
assertFalse
(
mock_save_grades
.
called
)
self
.
assertEqual
(
grade_a
.
url_name
,
grade_b
.
url_name
)
self
.
assertEqual
(
grade_a
.
url_name
,
grade_b
.
url_name
)
self
.
assertEqual
(
grade_a
.
all_total
,
grade_b
.
all_total
)
self
.
assertEqual
(
grade_a
.
all_total
,
grade_b
.
all_total
)
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
@ddt.data
(
(
True
,
True
),
(
True
,
True
),
(
True
,
False
),
(
True
,
False
),
...
...
lms/djangoapps/grades/tests/test_signals.py
View file @
31409940
...
@@ -3,6 +3,7 @@ Tests for the score change signals defined in the courseware models module.
...
@@ -3,6 +3,7 @@ Tests for the score change signals defined in the courseware models module.
"""
"""
import
ddt
import
ddt
from
django.conf
import
settings
from
django.test
import
TestCase
from
django.test
import
TestCase
from
mock
import
patch
,
MagicMock
from
mock
import
patch
,
MagicMock
from
unittest
import
skip
from
unittest
import
skip
...
@@ -169,6 +170,7 @@ class SubmissionSignalRelayTest(TestCase):
...
@@ -169,6 +170,7 @@ class SubmissionSignalRelayTest(TestCase):
self
.
signal_mock
.
assert_not_called
()
self
.
signal_mock
.
assert_not_called
()
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.ddt
@ddt.ddt
class
ScoreChangedUpdatesSubsectionGradeTest
(
ModuleStoreTestCase
):
class
ScoreChangedUpdatesSubsectionGradeTest
(
ModuleStoreTestCase
):
"""
"""
...
...
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
View file @
31409940
...
@@ -1641,6 +1641,8 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
...
@@ -1641,6 +1641,8 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
super
(
TestCertificateGeneration
,
self
)
.
setUp
()
super
(
TestCertificateGeneration
,
self
)
.
setUp
()
self
.
initialize_course
()
self
.
initialize_course
()
# disable persistent grades until TNL-5458 (reduces query counts)
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
def
test_certificate_generation_for_students
(
self
):
def
test_certificate_generation_for_students
(
self
):
"""
"""
Verify that certificates generated for all eligible students enrolled in a course.
Verify that certificates generated for all eligible students enrolled in a course.
...
...
lms/envs/test.py
View file @
31409940
...
@@ -298,6 +298,9 @@ OIDC_COURSE_HANDLER_CACHE_TIMEOUT = 0
...
@@ -298,6 +298,9 @@ OIDC_COURSE_HANDLER_CACHE_TIMEOUT = 0
FEATURES
[
'ENABLE_MOBILE_REST_API'
]
=
True
FEATURES
[
'ENABLE_MOBILE_REST_API'
]
=
True
FEATURES
[
'ENABLE_VIDEO_ABSTRACTION_LAYER_API'
]
=
True
FEATURES
[
'ENABLE_VIDEO_ABSTRACTION_LAYER_API'
]
=
True
########################### Grades #################################
FEATURES
[
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
]
=
True
###################### Payment ##############################3
###################### Payment ##############################3
# Enable fake payment processing page
# Enable fake payment processing page
FEATURES
[
'ENABLE_PAYMENT_FAKE'
]
=
True
FEATURES
[
'ENABLE_PAYMENT_FAKE'
]
=
True
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment