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
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
108 additions
and
70 deletions
+108
-70
lms/djangoapps/ccx/tests/test_field_override_performance.py
+1
-0
lms/djangoapps/courseware/tests/test_submitting_problems.py
+28
-8
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
+5
-8
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
'django.conf.settings.FEATURES'
,
{
'ENABLE_XBLOCK_VIEW_ENDPOINT'
:
True
,
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
# disable persistent grades until TNL-5458 (reduces queries)
}
)
@ddt.ddt
...
...
lms/djangoapps/courseware/tests/test_submitting_problems.py
View file @
31409940
...
...
@@ -25,6 +25,7 @@ from courseware.models import StudentModule, BaseStudentModuleHistory
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
lms.djangoapps.lms_xblock.runtime
import
quote_slashes
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.factories
import
CourseFactory
,
ItemFactory
from
xmodule.partitions.partitions
import
Group
,
UserPartition
...
...
@@ -143,9 +144,22 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
self
.
student_user
=
User
.
objects
.
get
(
email
=
self
.
student
)
self
.
factory
=
RequestFactory
()
# Disable the score change signal to prevent other components from being pulled into tests.
signal_patch
=
patch
(
'courseware.module_render.SCORE_CHANGED.send'
)
signal_patch
.
start
()
self
.
addCleanup
(
signal_patch
.
stop
)
self
.
score_changed_signal_patch
=
patch
(
'courseware.module_render.SCORE_CHANGED.send'
)
self
.
score_changed_signal_patch
.
start
()
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
):
"""
...
...
@@ -540,12 +554,18 @@ class TestCourseGrader(TestSubmittingProblems):
self
.
check_grade_percent
(
0.67
)
self
.
assertEqual
(
self
.
get_grade_summary
()[
'grade'
],
'B'
)
# But now we mock out a get_scores call, and watch as it overrides the
# score read from StudentModule and our student gets an A instead.
with
patch
(
'submissions.api.get_scores'
)
as
mock_get_scores
:
mock_get_scores
.
return_value
=
{
self
.
problem_location
(
'p3'
)
.
to_deprecated_string
():
(
1
,
1
)
# But now, set the score with the submissions API and watch
# as it overrides the score read from StudentModule and our
# student gets an A instead.
self
.
_stop_signal_patch
()
student_item
=
{
'student_id'
:
anonymous_id_for_user
(
self
.
student_user
,
self
.
course
.
id
),
'course_id'
:
unicode
(
self
.
course
.
id
),
'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'
)
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
31409940
...
...
@@ -1345,6 +1345,8 @@ class ProgressPageTests(ModuleStoreTestCase):
)
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
(
*
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
controlling persistent grades.
"""
from
config_models.models
import
ConfigurationModel
from
django.conf
import
settings
from
django.db.models
import
BooleanField
from
xmodule_django.models
import
CourseKeyField
...
...
@@ -29,6 +30,8 @@ class PersistentGradesEnabledFlag(ConfigurationModel):
If the flag is enabled and no course ID is given,
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
():
return
False
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
persistent grading feature.
"""
import
ddt
from
django.conf
import
settings
import
itertools
from
mock
import
patch
from
django.test
import
TestCase
from
opaque_keys.edx.locator
import
CourseLocator
...
...
@@ -10,6 +13,7 @@ from lms.djangoapps.grades.config.models import PersistentGradesEnabledFlag
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
class
PersistentGradesFeatureFlagTests
(
TestCase
):
"""
...
...
@@ -21,16 +25,11 @@ class PersistentGradesFeatureFlagTests(TestCase):
self
.
course_id_1
=
CourseLocator
(
org
=
"edx"
,
course
=
"course"
,
run
=
"run"
)
self
.
course_id_2
=
CourseLocator
(
org
=
"edx"
,
course
=
"course2"
,
run
=
"run"
)
@ddt.data
(
(
True
,
True
,
True
),
(
True
,
True
,
False
),
(
True
,
False
,
True
),
(
True
,
False
,
False
),
(
False
,
True
,
True
),
(
False
,
False
,
True
),
(
False
,
True
,
False
),
(
False
,
False
,
False
),
)
@ddt.data
(
*
itertools
.
product
(
(
True
,
False
),
(
True
,
False
),
(
True
,
False
),
))
@ddt.unpack
def
test_persistent_grades_feature_flags
(
self
,
global_flag
,
enabled_for_all_courses
,
enabled_for_course_1
):
with
persistent_grades_feature_flags
(
...
...
lms/djangoapps/grades/models.py
View file @
31409940
...
...
@@ -29,13 +29,16 @@ log = logging.getLogger(__name__)
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
):
super
(
BlockRecordSet
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
__new__
(
cls
,
blocks
):
return
super
(
BlockRecordList
,
cls
)
.
__new__
(
cls
,
tuple
(
blocks
))
def
__init__
(
self
,
blocks
):
super
(
BlockRecordList
,
self
)
.
__init__
(
blocks
)
self
.
_json
=
None
self
.
_hash
=
None
...
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
stable ordering.
"""
if
self
.
_json
is
None
:
sorted_blocks
=
sorted
(
self
,
key
=
attrgetter
(
'locator'
))
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
sorted_blocks
]
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
self
]
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
for
block_dict
in
list_of_block_dicts
:
...
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
@classmethod
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
)
course_key
=
data
[
'course_key'
]
...
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
)
return
cls
(
record_generator
)
@classmethod
def
from_list
(
cls
,
blocks
):
"""
Return a BlockRecordList from a list.
"""
return
cls
(
tuple
(
blocks
))
def
to_hash
(
self
):
"""
Return a hashed version of the list of block records.
...
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
"""
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
()})
return
model
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.
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
Argument 'blocks' should be a BlockRecordList.
"""
try
:
with
transaction
.
atomic
():
model
=
self
.
create_from_blockrecords
(
blocks
)
...
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
Returns the blocks_json data stored on this model as a list of
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
):
...
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
if
not
kwargs
.
get
(
'course_id'
,
None
):
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
(
visible_blocks_id
=
visible_blocks_hash
,
**
kwargs
...
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
Modify an existing PersistentSubsectionGrade object, saving the new
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
.
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
usage_id
=
kwargs
[
'item_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
(
sender
=
None
,
points_possible
=
points_possible
,
...
...
@@ -73,8 +71,6 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
usage_id
=
kwargs
[
'item_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
(
sender
=
None
,
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
from
lms.djangoapps.grades.models
import
(
BlockRecord
,
BlockRecord
Se
t
,
BlockRecord
Lis
t
,
PersistentSubsectionGrade
,
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}'
def
test_empty_block_record_set
(
self
):
brs
=
BlockRecord
Set
(
)
brs
=
BlockRecord
List
(()
)
self
.
assertFalse
(
brs
)
self
.
assertEqual
(
brs
.
to_json
(),
self
.
empty_json
)
self
.
assertEqual
(
BlockRecord
Se
t
.
from_json
(
self
.
empty_json
),
BlockRecord
Lis
t
.
from_json
(
self
.
empty_json
),
brs
)
...
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
"""
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
):
"""
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
()]
for
block_dict
in
list_of_block_dicts
:
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
...
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
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
same record
in the database.
When creating new vblocks,
different ordering of blocks produces
different records
in the database.
"""
stored_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
,
self
.
record_a
])
new_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
])
stored_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
,
self
.
record_a
])
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
(
stored_vblocks
.
hashed
,
repeat
_vblocks
.
hashed
)
self
.
assertEqual
s
(
stored_vblocks
.
pk
,
same_order
_vblocks
.
pk
)
self
.
assertEqual
s
(
stored_vblocks
.
hashed
,
same_order
_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
def
test_blocks_property
(
self
):
"""
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing
visible_blocks.blocks yields a copy of the initial array. Also, trying to set the blocks property should raise
an exception.
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing visible_blocks.blocks yields a copy of the initial array.
Also, trying to set the blocks property should raise
an exception.
"""
expected_blocks
=
[
self
.
record_a
,
self
.
record_b
]
visible_blocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
(
expected_blocks
)
self
.
assertEqual
(
BlockRecordSet
(
expected_blocks
)
,
visible_blocks
.
blocks
)
expected_blocks
=
(
self
.
record_a
,
self
.
record_b
)
visible_blocks
=
self
.
_create_block_record_list
(
expected_blocks
)
self
.
assertEqual
(
expected_blocks
,
visible_blocks
.
blocks
)
with
self
.
assertRaises
(
AttributeError
):
visible_blocks
.
blocks
=
expected_blocks
...
...
lms/djangoapps/grades/tests/test_new.py
View file @
31409940
...
...
@@ -3,6 +3,7 @@ Test saved subsection grade functionality.
"""
import
ddt
from
django.conf
import
settings
from
mock
import
patch
from
capa.tests.response_xml_factory
import
MultipleChoiceResponseXMLFactory
...
...
@@ -71,6 +72,7 @@ class TestCourseGradeFactory(GradeTestBase):
Test that CourseGrades are calculated properly
"""
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
(
True
,
True
),
(
True
,
False
),
...
...
@@ -107,12 +109,6 @@ class SubsectionGradeFactoryTest(GradeTestBase):
"""
Tests to ensure that a persistent subsection grade is created, saved, then fetched on re-request.
"""
with
persistent_grades_feature_flags
(
global_flag
=
True
,
enabled_for_all_courses
=
False
,
course_id
=
self
.
course
.
id
,
enabled_for_course
=
True
):
with
patch
(
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._save_grade'
,
wraps
=
self
.
subsection_grade_factory
.
_save_grade
# pylint: disable=protected-access
...
...
@@ -121,7 +117,7 @@ class SubsectionGradeFactoryTest(GradeTestBase):
'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._get_saved_grade'
,
wraps
=
self
.
subsection_grade_factory
.
_get_saved_grade
# pylint: disable=protected-access
)
as
mock_get_saved_grade
:
with
self
.
assertNumQueries
(
22
):
with
self
.
assertNumQueries
(
19
):
grade_a
=
self
.
subsection_grade_factory
.
create
(
self
.
sequence
,
self
.
course_structure
,
...
...
@@ -133,7 +129,7 @@ class SubsectionGradeFactoryTest(GradeTestBase):
mock_get_saved_grade
.
reset_mock
()
mock_save_grades
.
reset_mock
()
with
self
.
assertNumQueries
(
4
):
with
self
.
assertNumQueries
(
3
):
grade_b
=
self
.
subsection_grade_factory
.
create
(
self
.
sequence
,
self
.
course_structure
,
...
...
@@ -145,6 +141,7 @@ class SubsectionGradeFactoryTest(GradeTestBase):
self
.
assertEqual
(
grade_a
.
url_name
,
grade_b
.
url_name
)
self
.
assertEqual
(
grade_a
.
all_total
,
grade_b
.
all_total
)
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
(
True
,
True
),
(
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.
"""
import
ddt
from
django.conf
import
settings
from
django.test
import
TestCase
from
mock
import
patch
,
MagicMock
from
unittest
import
skip
...
...
@@ -169,6 +170,7 @@ class SubmissionSignalRelayTest(TestCase):
self
.
signal_mock
.
assert_not_called
()
@patch.dict
(
settings
.
FEATURES
,
{
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
:
False
})
@ddt.ddt
class
ScoreChangedUpdatesSubsectionGradeTest
(
ModuleStoreTestCase
):
"""
...
...
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
View file @
31409940
...
...
@@ -1641,6 +1641,8 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
super
(
TestCertificateGeneration
,
self
)
.
setUp
()
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
):
"""
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
FEATURES
[
'ENABLE_MOBILE_REST_API'
]
=
True
FEATURES
[
'ENABLE_VIDEO_ABSTRACTION_LAYER_API'
]
=
True
########################### Grades #################################
FEATURES
[
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
]
=
True
###################### Payment ##############################3
# Enable fake payment processing page
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