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
ae44f184
Commit
ae44f184
authored
Sep 06, 2017
by
Jeremy Bowman
Committed by
GitHub
Sep 06, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15951 from edx/jmbowman/ddt_cleanup
ddt usage cleanup
parents
d6e89e7b
fd6af6b0
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
431 additions
and
212 deletions
+431
-212
common/djangoapps/course_modes/tests/test_models.py
+8
-2
common/djangoapps/student/roles.py
+5
-1
common/djangoapps/student/tests/test_verification_status.py
+22
-17
common/djangoapps/student/tests/test_views.py
+2
-3
common/djangoapps/util/tests/test_db.py
+12
-6
common/test/utils.py
+27
-0
lms/djangoapps/certificates/tests/test_queue.py
+7
-6
lms/djangoapps/commerce/api/v1/tests/test_views.py
+8
-2
lms/djangoapps/courseware/tests/test_access.py
+11
-6
lms/djangoapps/courseware/tests/test_courses.py
+13
-5
lms/djangoapps/courseware/tests/test_module_render.py
+3
-3
lms/djangoapps/courseware/tests/test_video_handlers.py
+3
-0
lms/djangoapps/courseware/tests/test_video_mongo.py
+14
-8
lms/djangoapps/courseware/tests/test_views.py
+22
-9
lms/djangoapps/grades/tests/test_scores.py
+32
-0
lms/djangoapps/grades/tests/test_signals.py
+53
-32
lms/djangoapps/instructor_task/tests/test_api.py
+20
-11
lms/djangoapps/mobile_api/users/tests.py
+12
-7
lms/djangoapps/teams/tests/test_models.py
+20
-17
lms/djangoapps/verify_student/tests/test_views.py
+12
-4
openedx/core/djangoapps/content/block_structure/tests/helpers.py
+3
-0
openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py
+19
-6
openedx/core/djangoapps/credit/tests/test_signals.py
+12
-6
openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py
+55
-42
openedx/core/djangoapps/user_api/validation/tests/test_views.py
+10
-10
openedx/core/djangoapps/util/tests/test_user_messages.py
+6
-4
openedx/core/lib/xblock_builtin/xblock_discussion/tests.py
+9
-0
openedx/features/course_experience/tests/views/test_course_outline.py
+11
-5
No files found.
common/djangoapps/course_modes/tests/test_models.py
View file @
ae44f184
...
@@ -29,6 +29,11 @@ class CourseModeModelTest(TestCase):
...
@@ -29,6 +29,11 @@ class CourseModeModelTest(TestCase):
"""
"""
Tests for the CourseMode model
Tests for the CourseMode model
"""
"""
NOW
=
'now'
DATES
=
{
NOW
:
datetime
.
now
(),
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
CourseModeModelTest
,
self
)
.
setUp
()
super
(
CourseModeModelTest
,
self
)
.
setUp
()
...
@@ -317,10 +322,11 @@ class CourseModeModelTest(TestCase):
...
@@ -317,10 +322,11 @@ class CourseModeModelTest(TestCase):
CourseMode
.
PROFESSIONAL
,
CourseMode
.
PROFESSIONAL
,
CourseMode
.
NO_ID_PROFESSIONAL_MODE
CourseMode
.
NO_ID_PROFESSIONAL_MODE
),
),
(
datetime
.
now
()
,
None
),
(
NOW
,
None
),
))
))
@ddt.unpack
@ddt.unpack
def
test_invalid_mode_expiration
(
self
,
mode_slug
,
exp_dt
):
def
test_invalid_mode_expiration
(
self
,
mode_slug
,
exp_dt_name
):
exp_dt
=
self
.
DATES
[
exp_dt_name
]
is_error_expected
=
CourseMode
.
is_professional_slug
(
mode_slug
)
and
exp_dt
is
not
None
is_error_expected
=
CourseMode
.
is_professional_slug
(
mode_slug
)
and
exp_dt
is
not
None
try
:
try
:
self
.
create_mode
(
mode_slug
=
mode_slug
,
mode_name
=
mode_slug
.
title
(),
expiration_datetime
=
exp_dt
,
min_price
=
10
)
self
.
create_mode
(
mode_slug
=
mode_slug
,
mode_name
=
mode_slug
.
title
(),
expiration_datetime
=
exp_dt
,
min_price
=
10
)
...
...
common/djangoapps/student/roles.py
View file @
ae44f184
...
@@ -234,12 +234,16 @@ class CourseRole(RoleBase):
...
@@ -234,12 +234,16 @@ class CourseRole(RoleBase):
def
course_group_already_exists
(
self
,
course_key
):
def
course_group_already_exists
(
self
,
course_key
):
return
CourseAccessRole
.
objects
.
filter
(
org
=
course_key
.
org
,
course_id
=
course_key
)
.
exists
()
return
CourseAccessRole
.
objects
.
filter
(
org
=
course_key
.
org
,
course_id
=
course_key
)
.
exists
()
def
__repr__
(
self
):
return
'<{}: course_key={}>'
.
format
(
self
.
__class__
.
__name__
,
self
.
course_key
)
class
OrgRole
(
RoleBase
):
class
OrgRole
(
RoleBase
):
"""
"""
A named role in a particular org independent of course
A named role in a particular org independent of course
"""
"""
pass
def
__repr__
(
self
):
return
'<{}>'
.
format
(
self
.
__class__
.
__name__
)
@register_access_role
@register_access_role
...
...
common/djangoapps/student/tests/test_verification_status.py
View file @
ae44f184
...
@@ -33,8 +33,13 @@ from xmodule.modulestore.tests.factories import CourseFactory
...
@@ -33,8 +33,13 @@ from xmodule.modulestore.tests.factories import CourseFactory
class
TestCourseVerificationStatus
(
UrlResetMixin
,
ModuleStoreTestCase
):
class
TestCourseVerificationStatus
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""Tests for per-course verification status on the dashboard. """
"""Tests for per-course verification status on the dashboard. """
PAST
=
datetime
.
now
(
UTC
)
-
timedelta
(
days
=
5
)
PAST
=
'past'
FUTURE
=
datetime
.
now
(
UTC
)
+
timedelta
(
days
=
5
)
FUTURE
=
'future'
DATES
=
{
PAST
:
datetime
.
now
(
UTC
)
-
timedelta
(
days
=
5
),
FUTURE
:
datetime
.
now
(
UTC
)
+
timedelta
(
days
=
5
),
None
:
None
,
}
URLCONF_MODULES
=
[
'verify_student.urls'
]
URLCONF_MODULES
=
[
'verify_student.urls'
]
...
@@ -91,14 +96,14 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -91,14 +96,14 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
self
.
_assert_course_verification_status
(
VERIFY_STATUS_NEED_TO_VERIFY
)
self
.
_assert_course_verification_status
(
VERIFY_STATUS_NEED_TO_VERIFY
)
def
test_need_to_verify_expiration
(
self
):
def
test_need_to_verify_expiration
(
self
):
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
response
=
self
.
client
.
get
(
self
.
dashboard_url
)
response
=
self
.
client
.
get
(
self
.
dashboard_url
)
self
.
assertContains
(
response
,
self
.
BANNER_ALT_MESSAGES
[
VERIFY_STATUS_NEED_TO_VERIFY
])
self
.
assertContains
(
response
,
self
.
BANNER_ALT_MESSAGES
[
VERIFY_STATUS_NEED_TO_VERIFY
])
self
.
assertContains
(
response
,
"You only have 4 days left to verify for this course."
)
self
.
assertContains
(
response
,
"You only have 4 days left to verify for this course."
)
@ddt.data
(
None
,
FUTURE
)
@ddt.data
(
None
,
FUTURE
)
def
test_waiting_approval
(
self
,
expiration
):
def
test_waiting_approval
(
self
,
expiration
):
self
.
_setup_mode_and_enrollment
(
expiration
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
expiration
]
,
"verified"
)
# The student has submitted a photo verification
# The student has submitted a photo verification
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -110,7 +115,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -110,7 +115,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
@ddt.data
(
None
,
FUTURE
)
@ddt.data
(
None
,
FUTURE
)
def
test_fully_verified
(
self
,
expiration
):
def
test_fully_verified
(
self
,
expiration
):
self
.
_setup_mode_and_enrollment
(
expiration
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
expiration
]
,
"verified"
)
# The student has an approved verification
# The student has an approved verification
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -127,7 +132,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -127,7 +132,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_missed_verification_deadline
(
self
):
def
test_missed_verification_deadline
(
self
):
# Expiration date in the past
# Expiration date in the past
self
.
_setup_mode_and_enrollment
(
self
.
PAST
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
PAST
]
,
"verified"
)
# The student does NOT have an approved verification
# The student does NOT have an approved verification
# so the status should show that the student missed the deadline.
# so the status should show that the student missed the deadline.
...
@@ -135,7 +140,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -135,7 +140,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_missed_verification_deadline_verification_was_expired
(
self
):
def
test_missed_verification_deadline_verification_was_expired
(
self
):
# Expiration date in the past
# Expiration date in the past
self
.
_setup_mode_and_enrollment
(
self
.
PAST
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
PAST
]
,
"verified"
)
# Create a verification, but the expiration date of the verification
# Create a verification, but the expiration date of the verification
# occurred before the deadline.
# occurred before the deadline.
...
@@ -143,7 +148,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -143,7 +148,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
attempt
.
mark_ready
()
attempt
.
mark_ready
()
attempt
.
submit
()
attempt
.
submit
()
attempt
.
approve
()
attempt
.
approve
()
attempt
.
created_at
=
self
.
PAST
-
timedelta
(
days
=
900
)
attempt
.
created_at
=
self
.
DATES
[
self
.
PAST
]
-
timedelta
(
days
=
900
)
attempt
.
save
()
attempt
.
save
()
# The student didn't have an approved verification at the deadline,
# The student didn't have an approved verification at the deadline,
...
@@ -152,14 +157,14 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -152,14 +157,14 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_missed_verification_deadline_but_later_verified
(
self
):
def
test_missed_verification_deadline_but_later_verified
(
self
):
# Expiration date in the past
# Expiration date in the past
self
.
_setup_mode_and_enrollment
(
self
.
PAST
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
PAST
]
,
"verified"
)
# Successfully verify, but after the deadline has already passed
# Successfully verify, but after the deadline has already passed
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
.
mark_ready
()
attempt
.
mark_ready
()
attempt
.
submit
()
attempt
.
submit
()
attempt
.
approve
()
attempt
.
approve
()
attempt
.
created_at
=
self
.
PAST
-
timedelta
(
days
=
900
)
attempt
.
created_at
=
self
.
DATES
[
self
.
PAST
]
-
timedelta
(
days
=
900
)
attempt
.
save
()
attempt
.
save
()
# The student didn't have an approved verification at the deadline,
# The student didn't have an approved verification at the deadline,
...
@@ -168,7 +173,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -168,7 +173,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_verification_denied
(
self
):
def
test_verification_denied
(
self
):
# Expiration date in the future
# Expiration date in the future
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
# Create a verification with the specified status
# Create a verification with the specified status
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -182,7 +187,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -182,7 +187,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_verification_error
(
self
):
def
test_verification_error
(
self
):
# Expiration date in the future
# Expiration date in the future
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
# Create a verification with the specified status
# Create a verification with the specified status
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -196,7 +201,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -196,7 +201,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
@override_settings
(
VERIFY_STUDENT
=
{
"DAYS_GOOD_FOR"
:
5
,
"EXPIRING_SOON_WINDOW"
:
10
})
@override_settings
(
VERIFY_STUDENT
=
{
"DAYS_GOOD_FOR"
:
5
,
"EXPIRING_SOON_WINDOW"
:
10
})
def
test_verification_will_expire_by_deadline
(
self
):
def
test_verification_will_expire_by_deadline
(
self
):
# Expiration date in the future
# Expiration date in the future
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
# Create a verification attempt that:
# Create a verification attempt that:
# 1) Is current (submitted in the last year)
# 1) Is current (submitted in the last year)
...
@@ -213,7 +218,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -213,7 +218,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
@override_settings
(
VERIFY_STUDENT
=
{
"DAYS_GOOD_FOR"
:
5
,
"EXPIRING_SOON_WINDOW"
:
10
})
@override_settings
(
VERIFY_STUDENT
=
{
"DAYS_GOOD_FOR"
:
5
,
"EXPIRING_SOON_WINDOW"
:
10
})
def
test_reverification_submitted_with_current_approved_verificaiton
(
self
):
def
test_reverification_submitted_with_current_approved_verificaiton
(
self
):
# Expiration date in the future
# Expiration date in the future
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
# Create a verification attempt that is approved but expiring soon
# Create a verification attempt that is approved but expiring soon
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -236,7 +241,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -236,7 +241,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_verification_occurred_after_deadline
(
self
):
def
test_verification_occurred_after_deadline
(
self
):
# Expiration date in the past
# Expiration date in the past
self
.
_setup_mode_and_enrollment
(
self
.
PAST
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
PAST
]
,
"verified"
)
# The deadline has passed, and we've asked the student
# The deadline has passed, and we've asked the student
# to reverify (through the support team).
# to reverify (through the support team).
...
@@ -250,7 +255,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -250,7 +255,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
def
test_with_two_verifications
(
self
):
def
test_with_two_verifications
(
self
):
# checking if a user has two verification and but most recent verification course deadline is expired
# checking if a user has two verification and but most recent verification course deadline is expired
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
self
.
_setup_mode_and_enrollment
(
self
.
DATES
[
self
.
FUTURE
]
,
"verified"
)
# The student has an approved verification
# The student has an approved verification
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
...
@@ -274,7 +279,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -274,7 +279,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
CourseModeFactory
.
create
(
CourseModeFactory
.
create
(
course_id
=
course2
.
id
,
course_id
=
course2
.
id
,
mode_slug
=
"verified"
,
mode_slug
=
"verified"
,
expiration_datetime
=
self
.
PAST
expiration_datetime
=
self
.
DATES
[
self
.
PAST
]
)
)
CourseEnrollmentFactory
(
CourseEnrollmentFactory
(
course_id
=
course2
.
id
,
course_id
=
course2
.
id
,
...
...
common/djangoapps/student/tests/test_views.py
View file @
ae44f184
...
@@ -297,19 +297,18 @@ class StudentDashboardTests(SharedModuleStoreTestCase):
...
@@ -297,19 +297,18 @@ class StudentDashboardTests(SharedModuleStoreTestCase):
@patch.multiple
(
'django.conf.settings'
,
**
MOCK_SETTINGS
)
@patch.multiple
(
'django.conf.settings'
,
**
MOCK_SETTINGS
)
@ddt.data
(
@ddt.data
(
*
itertools
.
product
(
*
itertools
.
product
(
[
TOMORROW
],
[
True
,
False
],
[
True
,
False
],
[
True
,
False
],
[
True
,
False
],
[
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
],
[
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
],
)
)
)
)
@ddt.unpack
@ddt.unpack
def
test_sharing_icons_for_future_course
(
self
,
s
tart_date
,
s
et_marketing
,
set_social_sharing
,
modulestore_type
):
def
test_sharing_icons_for_future_course
(
self
,
set_marketing
,
set_social_sharing
,
modulestore_type
):
"""
"""
Verify that the course sharing icons show up if course is starting in future and
Verify that the course sharing icons show up if course is starting in future and
any of marketing or social sharing urls are set.
any of marketing or social sharing urls are set.
"""
"""
self
.
course
=
CourseFactory
.
create
(
start
=
s
tart_date
,
emit_signals
=
True
,
default_store
=
modulestore_type
)
self
.
course
=
CourseFactory
.
create
(
start
=
s
elf
.
TOMORROW
,
emit_signals
=
True
,
default_store
=
modulestore_type
)
self
.
course_enrollment
=
CourseEnrollmentFactory
(
course_id
=
self
.
course
.
id
,
user
=
self
.
user
)
self
.
course_enrollment
=
CourseEnrollmentFactory
(
course_id
=
self
.
course
.
id
,
user
=
self
.
user
)
self
.
set_course_sharing_urls
(
set_marketing
,
set_social_sharing
)
self
.
set_course_sharing_urls
(
set_marketing
,
set_social_sharing
)
...
...
common/djangoapps/util/tests/test_db.py
View file @
ae44f184
...
@@ -31,20 +31,26 @@ class TransactionManagersTestCase(TransactionTestCase):
...
@@ -31,20 +31,26 @@ class TransactionManagersTestCase(TransactionTestCase):
To test do: "./manage.py lms --settings=test_with_mysql test util.tests.test_db"
To test do: "./manage.py lms --settings=test_with_mysql test util.tests.test_db"
"""
"""
DECORATORS
=
{
'outer_atomic'
:
outer_atomic
(),
'outer_atomic_read_committed'
:
outer_atomic
(
read_committed
=
True
),
'commit_on_success'
:
commit_on_success
(),
'commit_on_success_read_committed'
:
commit_on_success
(
read_committed
=
True
),
}
@ddt.data
(
@ddt.data
(
(
outer_atomic
()
,
IntegrityError
,
None
,
True
),
(
'outer_atomic'
,
IntegrityError
,
None
,
True
),
(
outer_atomic
(
read_committed
=
True
)
,
type
(
None
),
False
,
True
),
(
'outer_atomic_read_committed'
,
type
(
None
),
False
,
True
),
(
commit_on_success
()
,
IntegrityError
,
None
,
True
),
(
'commit_on_success'
,
IntegrityError
,
None
,
True
),
(
commit_on_success
(
read_committed
=
True
)
,
type
(
None
),
False
,
True
),
(
'commit_on_success_read_committed'
,
type
(
None
),
False
,
True
),
)
)
@ddt.unpack
@ddt.unpack
def
test_concurrent_requests
(
self
,
transaction_decorator
,
exception_class
,
created_in_1
,
created_in_2
):
def
test_concurrent_requests
(
self
,
transaction_decorator
_name
,
exception_class
,
created_in_1
,
created_in_2
):
"""
"""
Test that when isolation level is set to READ COMMITTED get_or_create()
Test that when isolation level is set to READ COMMITTED get_or_create()
for the same row in concurrent requests does not raise an IntegrityError.
for the same row in concurrent requests does not raise an IntegrityError.
"""
"""
transaction_decorator
=
self
.
DECORATORS
[
transaction_decorator_name
]
if
connection
.
vendor
!=
'mysql'
:
if
connection
.
vendor
!=
'mysql'
:
raise
unittest
.
SkipTest
(
'Only works on MySQL.'
)
raise
unittest
.
SkipTest
(
'Only works on MySQL.'
)
...
...
common/test/utils.py
View file @
ae44f184
"""
"""
General testing utilities.
General testing utilities.
"""
"""
import
functools
import
sys
import
sys
from
contextlib
import
contextmanager
from
contextlib
import
contextmanager
...
@@ -124,3 +125,29 @@ class MockS3Mixin(object):
...
@@ -124,3 +125,29 @@ class MockS3Mixin(object):
def
tearDown
(
self
):
def
tearDown
(
self
):
self
.
_mock_s3
.
stop
()
self
.
_mock_s3
.
stop
()
super
(
MockS3Mixin
,
self
)
.
tearDown
()
super
(
MockS3Mixin
,
self
)
.
tearDown
()
class
reprwrapper
(
object
):
"""
Wrapper class for functions that need a normalized string representation.
"""
def
__init__
(
self
,
func
):
self
.
_func
=
func
self
.
repr
=
'Func: {}'
.
format
(
func
.
__name__
)
functools
.
update_wrapper
(
self
,
func
)
def
__call__
(
self
,
*
args
,
**
kw
):
return
self
.
_func
(
*
args
,
**
kw
)
def
__repr__
(
self
):
return
self
.
repr
def
normalize_repr
(
func
):
"""
Function decorator used to normalize its string representation.
Used to wrap functions used as ddt parameters, so pytest-xdist
doesn't complain about the sequence of discovered tests differing
between worker processes.
"""
return
reprwrapper
(
func
)
lms/djangoapps/certificates/tests/test_queue.py
View file @
ae44f184
...
@@ -207,42 +207,42 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
...
@@ -207,42 +207,42 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
# Eligible and should stay that way
# Eligible and should stay that way
(
(
CertificateStatuses
.
downloadable
,
CertificateStatuses
.
downloadable
,
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
2
),
timedelta
(
days
=-
2
),
'Pass'
,
'Pass'
,
CertificateStatuses
.
generating
CertificateStatuses
.
generating
),
),
# Ensure that certs in the wrong state can be fixed by regeneration
# Ensure that certs in the wrong state can be fixed by regeneration
(
(
CertificateStatuses
.
downloadable
,
CertificateStatuses
.
downloadable
,
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
hours
=
1
),
timedelta
(
hours
=-
1
),
'Pass'
,
'Pass'
,
CertificateStatuses
.
audit_passing
CertificateStatuses
.
audit_passing
),
),
# Ineligible and should stay that way
# Ineligible and should stay that way
(
(
CertificateStatuses
.
audit_passing
,
CertificateStatuses
.
audit_passing
,
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
hours
=
1
),
timedelta
(
hours
=-
1
),
'Pass'
,
'Pass'
,
CertificateStatuses
.
audit_passing
CertificateStatuses
.
audit_passing
),
),
# As above
# As above
(
(
CertificateStatuses
.
audit_notpassing
,
CertificateStatuses
.
audit_notpassing
,
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
hours
=
1
),
timedelta
(
hours
=-
1
),
'Pass'
,
'Pass'
,
CertificateStatuses
.
audit_passing
CertificateStatuses
.
audit_passing
),
),
# As above
# As above
(
(
CertificateStatuses
.
audit_notpassing
,
CertificateStatuses
.
audit_notpassing
,
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
hours
=
1
),
timedelta
(
hours
=-
1
),
None
,
None
,
CertificateStatuses
.
audit_notpassing
CertificateStatuses
.
audit_notpassing
),
),
)
)
@ddt.unpack
@ddt.unpack
@override_settings
(
AUDIT_CERT_CUTOFF_DATE
=
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
1
))
@override_settings
(
AUDIT_CERT_CUTOFF_DATE
=
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
1
))
def
test_regen_audit_certs_eligibility
(
self
,
status
,
created_d
ate
,
grade
,
expected_status
):
def
test_regen_audit_certs_eligibility
(
self
,
status
,
created_d
elta
,
grade
,
expected_status
):
"""
"""
Test that existing audit certificates remain eligible even if cert
Test that existing audit certificates remain eligible even if cert
generation is re-run.
generation is re-run.
...
@@ -254,6 +254,7 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
...
@@ -254,6 +254,7 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
is_active
=
True
,
is_active
=
True
,
mode
=
CourseMode
.
AUDIT
,
mode
=
CourseMode
.
AUDIT
,
)
)
created_date
=
datetime
.
now
(
pytz
.
UTC
)
+
created_delta
with
freezegun
.
freeze_time
(
created_date
):
with
freezegun
.
freeze_time
(
created_date
):
GeneratedCertificateFactory
(
GeneratedCertificateFactory
(
user
=
self
.
user_2
,
user
=
self
.
user_2
,
...
...
lms/djangoapps/commerce/api/v1/tests/test_views.py
View file @
ae44f184
...
@@ -106,6 +106,11 @@ class CourseListViewTests(CourseApiViewTestMixin, ModuleStoreTestCase):
...
@@ -106,6 +106,11 @@ class CourseListViewTests(CourseApiViewTestMixin, ModuleStoreTestCase):
@ddt.ddt
@ddt.ddt
class
CourseRetrieveUpdateViewTests
(
CourseApiViewTestMixin
,
ModuleStoreTestCase
):
class
CourseRetrieveUpdateViewTests
(
CourseApiViewTestMixin
,
ModuleStoreTestCase
):
""" Tests for CourseRetrieveUpdateView. """
""" Tests for CourseRetrieveUpdateView. """
NOW
=
'now'
DATES
=
{
NOW
:
datetime
.
now
(),
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
CourseRetrieveUpdateViewTests
,
self
)
.
setUp
()
super
(
CourseRetrieveUpdateViewTests
,
self
)
.
setUp
()
...
@@ -276,12 +281,13 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
...
@@ -276,12 +281,13 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
@ddt.data
(
*
itertools
.
product
(
@ddt.data
(
*
itertools
.
product
(
(
'honor'
,
'audit'
,
'verified'
,
'professional'
,
'no-id-professional'
),
(
'honor'
,
'audit'
,
'verified'
,
'professional'
,
'no-id-professional'
),
(
datetime
.
now
()
,
None
),
(
NOW
,
None
),
))
))
@ddt.unpack
@ddt.unpack
def
test_update_professional_expiration
(
self
,
mode_slug
,
expiration_datetime
):
def
test_update_professional_expiration
(
self
,
mode_slug
,
expiration_datetime
_name
):
""" Verify that pushing a mode with a professional certificate and an expiration datetime
""" Verify that pushing a mode with a professional certificate and an expiration datetime
will be rejected (this is not allowed). """
will be rejected (this is not allowed). """
expiration_datetime
=
self
.
DATES
[
expiration_datetime_name
]
mode
=
self
.
_serialize_course_mode
(
mode
=
self
.
_serialize_course_mode
(
CourseMode
(
CourseMode
(
mode_slug
=
mode_slug
,
mode_slug
=
mode_slug
,
...
...
lms/djangoapps/courseware/tests/test_access.py
View file @
ae44f184
...
@@ -162,9 +162,14 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -162,9 +162,14 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
"""
"""
Tests for the various access controls on the student dashboard
Tests for the various access controls on the student dashboard
"""
"""
TOMORROW
=
datetime
.
datetime
.
now
(
pytz
.
utc
)
+
datetime
.
timedelta
(
days
=
1
)
TOMORROW
=
'tomorrow'
YESTERDAY
=
datetime
.
datetime
.
now
(
pytz
.
utc
)
-
datetime
.
timedelta
(
days
=
1
)
YESTERDAY
=
'yesterday'
MODULESTORE
=
TEST_DATA_SPLIT_MODULESTORE
MODULESTORE
=
TEST_DATA_SPLIT_MODULESTORE
DATES
=
{
TOMORROW
:
datetime
.
datetime
.
now
(
pytz
.
utc
)
+
datetime
.
timedelta
(
days
=
1
),
YESTERDAY
:
datetime
.
datetime
.
now
(
pytz
.
utc
)
-
datetime
.
timedelta
(
days
=
1
),
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
AccessTestCase
,
self
)
.
setUp
()
super
(
AccessTestCase
,
self
)
.
setUp
()
...
@@ -439,7 +444,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -439,7 +444,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
visible_to_staff_only
=
visible_to_staff_only
mock_unit
.
visible_to_staff_only
=
visible_to_staff_only
mock_unit
.
start
=
s
tart
mock_unit
.
start
=
s
elf
.
DATES
[
start
]
mock_unit
.
merged_group_access
=
{}
mock_unit
.
merged_group_access
=
{}
self
.
verify_access
(
mock_unit
,
expected_access
,
expected_error_type
)
self
.
verify_access
(
mock_unit
,
expected_access
,
expected_error_type
)
...
@@ -448,7 +453,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -448,7 +453,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
mock_unit
=
Mock
(
user_partitions
=
[])
mock_unit
=
Mock
(
user_partitions
=
[])
mock_unit
.
_class_tags
=
{}
mock_unit
.
_class_tags
=
{}
mock_unit
.
days_early_for_beta
=
2
mock_unit
.
days_early_for_beta
=
2
mock_unit
.
start
=
self
.
TOMORROW
mock_unit
.
start
=
self
.
DATES
[
self
.
TOMORROW
]
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
merged_group_access
=
{}
mock_unit
.
merged_group_access
=
{}
...
@@ -465,7 +470,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -465,7 +470,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
start
=
s
tart
mock_unit
.
start
=
s
elf
.
DATES
[
start
]
mock_unit
.
merged_group_access
=
{}
mock_unit
.
merged_group_access
=
{}
self
.
verify_access
(
mock_unit
,
True
)
self
.
verify_access
(
mock_unit
,
True
)
...
@@ -486,7 +491,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -486,7 +491,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
=
Mock
(
location
=
self
.
course
.
location
,
user_partitions
=
[])
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
_class_tags
=
{}
# Needed for detached check in _has_access_descriptor
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
visible_to_staff_only
=
False
mock_unit
.
start
=
s
tart
mock_unit
.
start
=
s
elf
.
DATES
[
start
]
mock_unit
.
merged_group_access
=
{}
mock_unit
.
merged_group_access
=
{}
self
.
verify_access
(
mock_unit
,
expected_access
,
expected_error_type
)
self
.
verify_access
(
mock_unit
,
expected_access
,
expected_error_type
)
...
...
lms/djangoapps/courseware/tests/test_courses.py
View file @
ae44f184
...
@@ -49,6 +49,12 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
...
@@ -49,6 +49,12 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
class
CoursesTest
(
ModuleStoreTestCase
):
class
CoursesTest
(
ModuleStoreTestCase
):
"""Test methods related to fetching courses."""
"""Test methods related to fetching courses."""
ENABLED_SIGNALS
=
[
'course_published'
]
ENABLED_SIGNALS
=
[
'course_published'
]
GET_COURSE_WITH_ACCESS
=
'get_course_with_access'
GET_COURSE_OVERVIEW_WITH_ACCESS
=
'get_course_overview_with_access'
COURSE_ACCESS_FUNCS
=
{
GET_COURSE_WITH_ACCESS
:
get_course_with_access
,
GET_COURSE_OVERVIEW_WITH_ACCESS
:
get_course_overview_with_access
,
}
@override_settings
(
CMS_BASE
=
CMS_BASE_TEST
)
@override_settings
(
CMS_BASE
=
CMS_BASE_TEST
)
def
test_get_cms_course_block_link
(
self
):
def
test_get_cms_course_block_link
(
self
):
...
@@ -64,8 +70,9 @@ class CoursesTest(ModuleStoreTestCase):
...
@@ -64,8 +70,9 @@ class CoursesTest(ModuleStoreTestCase):
cms_url
=
u"//{}/course/{}"
.
format
(
CMS_BASE_TEST
,
unicode
(
self
.
course
.
location
))
cms_url
=
u"//{}/course/{}"
.
format
(
CMS_BASE_TEST
,
unicode
(
self
.
course
.
location
))
self
.
assertEqual
(
cms_url
,
get_cms_block_link
(
self
.
course
,
'course'
))
self
.
assertEqual
(
cms_url
,
get_cms_block_link
(
self
.
course
,
'course'
))
@ddt.data
(
get_course_with_access
,
get_course_overview_with_access
)
@ddt.data
(
GET_COURSE_WITH_ACCESS
,
GET_COURSE_OVERVIEW_WITH_ACCESS
)
def
test_get_course_func_with_access_error
(
self
,
course_access_func
):
def
test_get_course_func_with_access_error
(
self
,
course_access_func_name
):
course_access_func
=
self
.
COURSE_ACCESS_FUNCS
[
course_access_func_name
]
user
=
UserFactory
.
create
()
user
=
UserFactory
.
create
()
course
=
CourseFactory
.
create
(
visible_to_staff_only
=
True
)
course
=
CourseFactory
.
create
(
visible_to_staff_only
=
True
)
...
@@ -76,11 +83,12 @@ class CoursesTest(ModuleStoreTestCase):
...
@@ -76,11 +83,12 @@ class CoursesTest(ModuleStoreTestCase):
self
.
assertFalse
(
error
.
exception
.
access_response
.
has_access
)
self
.
assertFalse
(
error
.
exception
.
access_response
.
has_access
)
@ddt.data
(
@ddt.data
(
(
get_course_with_access
,
1
),
(
GET_COURSE_WITH_ACCESS
,
1
),
(
get_course_overview_with_access
,
0
),
(
GET_COURSE_OVERVIEW_WITH_ACCESS
,
0
),
)
)
@ddt.unpack
@ddt.unpack
def
test_get_course_func_with_access
(
self
,
course_access_func
,
num_mongo_calls
):
def
test_get_course_func_with_access
(
self
,
course_access_func_name
,
num_mongo_calls
):
course_access_func
=
self
.
COURSE_ACCESS_FUNCS
[
course_access_func_name
]
user
=
UserFactory
.
create
()
user
=
UserFactory
.
create
()
course
=
CourseFactory
.
create
(
emit_signals
=
True
)
course
=
CourseFactory
.
create
(
emit_signals
=
True
)
with
check_mongo_calls
(
num_mongo_calls
):
with
check_mongo_calls
(
num_mongo_calls
):
...
...
lms/djangoapps/courseware/tests/test_module_render.py
View file @
ae44f184
...
@@ -1570,11 +1570,11 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
...
@@ -1570,11 +1570,11 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
PER_COURSE_ANONYMIZED_DESCRIPTORS
=
(
LTIDescriptor
,
)
PER_COURSE_ANONYMIZED_DESCRIPTORS
=
(
LTIDescriptor
,
)
# The "set" here is to work around the bug that load_classes returns duplicates for multiply-de
lc
ared classes.
# The "set" here is to work around the bug that load_classes returns duplicates for multiply-de
cl
ared classes.
PER_STUDENT_ANONYMIZED_DESCRIPTORS
=
set
(
PER_STUDENT_ANONYMIZED_DESCRIPTORS
=
s
orted
(
s
et
(
class_
for
(
name
,
class_
)
in
XModuleDescriptor
.
load_classes
()
class_
for
(
name
,
class_
)
in
XModuleDescriptor
.
load_classes
()
if
not
issubclass
(
class_
,
PER_COURSE_ANONYMIZED_DESCRIPTORS
)
if
not
issubclass
(
class_
,
PER_COURSE_ANONYMIZED_DESCRIPTORS
)
)
)
,
key
=
str
)
@attr
(
shard
=
1
)
@attr
(
shard
=
1
)
...
...
lms/djangoapps/courseware/tests/test_video_handlers.py
View file @
ae44f184
...
@@ -13,6 +13,7 @@ from mock import MagicMock, Mock, patch
...
@@ -13,6 +13,7 @@ from mock import MagicMock, Mock, patch
from
nose.plugins.attrib
import
attr
from
nose.plugins.attrib
import
attr
from
webob
import
Request
from
webob
import
Request
from
common.test.utils
import
normalize_repr
from
openedx.core.djangoapps.contentserver.caching
import
del_cached_content
from
openedx.core.djangoapps.contentserver.caching
import
del_cached_content
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.django
import
contentstore
...
@@ -105,6 +106,7 @@ def _upload_file(subs_file, location, filename):
...
@@ -105,6 +106,7 @@ def _upload_file(subs_file, location, filename):
del_cached_content
(
content
.
location
)
del_cached_content
(
content
.
location
)
@normalize_repr
def
attach_sub
(
item
,
filename
):
def
attach_sub
(
item
,
filename
):
"""
"""
Attach `en` transcript.
Attach `en` transcript.
...
@@ -112,6 +114,7 @@ def attach_sub(item, filename):
...
@@ -112,6 +114,7 @@ def attach_sub(item, filename):
item
.
sub
=
filename
item
.
sub
=
filename
@normalize_repr
def
attach_bumper_transcript
(
item
,
filename
,
lang
=
"en"
):
def
attach_bumper_transcript
(
item
,
filename
,
lang
=
"en"
):
"""
"""
Attach bumper transcript.
Attach bumper transcript.
...
...
lms/djangoapps/courseware/tests/test_video_mongo.py
View file @
ae44f184
...
@@ -17,6 +17,7 @@ from path import Path as path
...
@@ -17,6 +17,7 @@ from path import Path as path
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.exceptions
import
NotFoundError
from
xmodule.exceptions
import
NotFoundError
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.tests.django_utils
import
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
from
xmodule.modulestore.tests.django_utils
import
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
from
xmodule.tests.test_import
import
DummySystem
from
xmodule.tests.test_import
import
DummySystem
...
@@ -29,6 +30,11 @@ from .helpers import BaseTestXmodule
...
@@ -29,6 +30,11 @@ from .helpers import BaseTestXmodule
from
.test_video_handlers
import
TestVideo
from
.test_video_handlers
import
TestVideo
from
.test_video_xml
import
SOURCE_XML
from
.test_video_xml
import
SOURCE_XML
MODULESTORES
=
{
ModuleStoreEnum
.
Type
.
mongo
:
TEST_DATA_MONGO_MODULESTORE
,
ModuleStoreEnum
.
Type
.
split
:
TEST_DATA_SPLIT_MODULESTORE
,
}
@attr
(
shard
=
1
)
@attr
(
shard
=
1
)
class
TestVideoYouTube
(
TestVideo
):
class
TestVideoYouTube
(
TestVideo
):
...
@@ -1162,14 +1168,14 @@ class TestEditorSavedMethod(BaseTestXmodule):
...
@@ -1162,14 +1168,14 @@ class TestEditorSavedMethod(BaseTestXmodule):
self
.
test_dir
=
path
(
__file__
)
.
abspath
()
.
dirname
()
.
dirname
()
.
dirname
()
.
dirname
()
.
dirname
()
self
.
test_dir
=
path
(
__file__
)
.
abspath
()
.
dirname
()
.
dirname
()
.
dirname
()
.
dirname
()
.
dirname
()
self
.
file_path
=
self
.
test_dir
+
'/common/test/data/uploads/'
+
self
.
file_name
self
.
file_path
=
self
.
test_dir
+
'/common/test/data/uploads/'
+
self
.
file_name
@ddt.data
(
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_editor_saved_when_html5_sub_not_exist
(
self
,
default_store
):
def
test_editor_saved_when_html5_sub_not_exist
(
self
,
default_store
):
"""
"""
When there is youtube_sub exist but no html5_sub present for
When there is youtube_sub exist but no html5_sub present for
html5_sources, editor_saved function will generate new html5_sub
html5_sources, editor_saved function will generate new html5_sub
for video.
for video.
"""
"""
self
.
MODULESTORE
=
default_store
# pylint: disable=invalid-name
self
.
MODULESTORE
=
MODULESTORES
[
default_store
]
# pylint: disable=invalid-name
self
.
initialize_module
(
metadata
=
self
.
metadata
)
self
.
initialize_module
(
metadata
=
self
.
metadata
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
with
open
(
self
.
file_path
,
"r"
)
as
myfile
:
with
open
(
self
.
file_path
,
"r"
)
as
myfile
:
...
@@ -1184,13 +1190,13 @@ class TestEditorSavedMethod(BaseTestXmodule):
...
@@ -1184,13 +1190,13 @@ class TestEditorSavedMethod(BaseTestXmodule):
self
.
assertIsInstance
(
Transcript
.
get_asset
(
item
.
location
,
'subs_3_yD_cEKoCk.srt.sjson'
),
StaticContent
)
self
.
assertIsInstance
(
Transcript
.
get_asset
(
item
.
location
,
'subs_3_yD_cEKoCk.srt.sjson'
),
StaticContent
)
self
.
assertIsInstance
(
Transcript
.
get_asset
(
item
.
location
,
'subs_video.srt.sjson'
),
StaticContent
)
self
.
assertIsInstance
(
Transcript
.
get_asset
(
item
.
location
,
'subs_video.srt.sjson'
),
StaticContent
)
@ddt.data
(
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_editor_saved_when_youtube_and_html5_subs_exist
(
self
,
default_store
):
def
test_editor_saved_when_youtube_and_html5_subs_exist
(
self
,
default_store
):
"""
"""
When both youtube_sub and html5_sub already exist then no new
When both youtube_sub and html5_sub already exist then no new
sub will be generated by editor_saved function.
sub will be generated by editor_saved function.
"""
"""
self
.
MODULESTORE
=
default_store
self
.
MODULESTORE
=
MODULESTORES
[
default_store
]
self
.
initialize_module
(
metadata
=
self
.
metadata
)
self
.
initialize_module
(
metadata
=
self
.
metadata
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
with
open
(
self
.
file_path
,
"r"
)
as
myfile
:
with
open
(
self
.
file_path
,
"r"
)
as
myfile
:
...
@@ -1205,12 +1211,12 @@ class TestEditorSavedMethod(BaseTestXmodule):
...
@@ -1205,12 +1211,12 @@ class TestEditorSavedMethod(BaseTestXmodule):
item
.
editor_saved
(
self
.
user
,
old_metadata
,
None
)
item
.
editor_saved
(
self
.
user
,
old_metadata
,
None
)
self
.
assertFalse
(
manage_video_subtitles_save
.
called
)
self
.
assertFalse
(
manage_video_subtitles_save
.
called
)
@ddt.data
(
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_editor_saved_with_unstripped_video_id
(
self
,
default_store
):
def
test_editor_saved_with_unstripped_video_id
(
self
,
default_store
):
"""
"""
Verify editor saved when video id contains spaces/tabs.
Verify editor saved when video id contains spaces/tabs.
"""
"""
self
.
MODULESTORE
=
default_store
self
.
MODULESTORE
=
MODULESTORES
[
default_store
]
stripped_video_id
=
unicode
(
uuid4
())
stripped_video_id
=
unicode
(
uuid4
())
unstripped_video_id
=
u'{video_id}{tabs}'
.
format
(
video_id
=
stripped_video_id
,
tabs
=
u'
\t\t\t
'
)
unstripped_video_id
=
u'{video_id}{tabs}'
.
format
(
video_id
=
stripped_video_id
,
tabs
=
u'
\t\t\t
'
)
self
.
metadata
.
update
({
self
.
metadata
.
update
({
...
@@ -1226,14 +1232,14 @@ class TestEditorSavedMethod(BaseTestXmodule):
...
@@ -1226,14 +1232,14 @@ class TestEditorSavedMethod(BaseTestXmodule):
item
.
editor_saved
(
self
.
user
,
old_metadata
,
None
)
item
.
editor_saved
(
self
.
user
,
old_metadata
,
None
)
self
.
assertEqual
(
item
.
edx_video_id
,
stripped_video_id
)
self
.
assertEqual
(
item
.
edx_video_id
,
stripped_video_id
)
@ddt.data
(
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_SPLIT_MODULESTORE
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
@patch
(
'xmodule.video_module.video_module.edxval_api.get_url_for_profile'
,
Mock
(
return_value
=
'test_yt_id'
))
@patch
(
'xmodule.video_module.video_module.edxval_api.get_url_for_profile'
,
Mock
(
return_value
=
'test_yt_id'
))
def
test_editor_saved_with_yt_val_profile
(
self
,
default_store
):
def
test_editor_saved_with_yt_val_profile
(
self
,
default_store
):
"""
"""
Verify editor saved overrides `youtube_id_1_0` when a youtube val profile is there
Verify editor saved overrides `youtube_id_1_0` when a youtube val profile is there
for a given `edx_video_id`.
for a given `edx_video_id`.
"""
"""
self
.
MODULESTORE
=
default_store
self
.
MODULESTORE
=
MODULESTORES
[
default_store
]
self
.
initialize_module
(
metadata
=
self
.
metadata
)
self
.
initialize_module
(
metadata
=
self
.
metadata
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
item
=
self
.
store
.
get_item
(
self
.
item_descriptor
.
location
)
self
.
assertEqual
(
item
.
youtube_id_1_0
,
'3_yD_cEKoCk'
)
self
.
assertEqual
(
item
.
youtube_id_1_0
,
'3_yD_cEKoCk'
)
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
ae44f184
...
@@ -251,6 +251,11 @@ class ViewsTestCase(ModuleStoreTestCase):
...
@@ -251,6 +251,11 @@ class ViewsTestCase(ModuleStoreTestCase):
"""
"""
Tests for views.py methods.
Tests for views.py methods.
"""
"""
YESTERDAY
=
'yesterday'
DATES
=
{
YESTERDAY
:
datetime
.
now
(
UTC
)
-
timedelta
(
days
=
1
),
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
ViewsTestCase
,
self
)
.
setUp
()
super
(
ViewsTestCase
,
self
)
.
setUp
()
...
@@ -751,7 +756,7 @@ class ViewsTestCase(ModuleStoreTestCase):
...
@@ -751,7 +756,7 @@ class ViewsTestCase(ModuleStoreTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertIn
(
'Financial Assistance Application'
,
response
.
content
)
self
.
assertIn
(
'Financial Assistance Application'
,
response
.
content
)
@ddt.data
(([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
AUDIT
,
True
,
datetime
.
now
(
UTC
)
-
timedelta
(
days
=
1
)
),
@ddt.data
(([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
AUDIT
,
True
,
YESTERDAY
),
([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
VERIFIED
,
True
,
None
),
([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
VERIFIED
,
True
,
None
),
([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
AUDIT
,
False
,
None
),
([
CourseMode
.
AUDIT
,
CourseMode
.
VERIFIED
],
CourseMode
.
AUDIT
,
False
,
None
),
([
CourseMode
.
AUDIT
],
CourseMode
.
AUDIT
,
False
,
None
))
([
CourseMode
.
AUDIT
],
CourseMode
.
AUDIT
,
False
,
None
))
...
@@ -770,7 +775,7 @@ class ViewsTestCase(ModuleStoreTestCase):
...
@@ -770,7 +775,7 @@ class ViewsTestCase(ModuleStoreTestCase):
# Create Course Modes
# Create Course Modes
for
mode
in
course_modes
:
for
mode
in
course_modes
:
CourseModeFactory
.
create
(
mode_slug
=
mode
,
course_id
=
course
.
id
,
expiration_datetime
=
expiration
)
CourseModeFactory
.
create
(
mode_slug
=
mode
,
course_id
=
course
.
id
,
expiration_datetime
=
self
.
DATES
[
expiration
]
)
# Enroll user in the course
# Enroll user in the course
CourseEnrollmentFactory
(
course_id
=
course
.
id
,
user
=
self
.
user
,
mode
=
enrollment_mode
)
CourseEnrollmentFactory
(
course_id
=
course
.
id
,
user
=
self
.
user
,
mode
=
enrollment_mode
)
...
@@ -1705,10 +1710,16 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
...
@@ -1705,10 +1710,16 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
# Constants used in the test data
# Constants used in the test data
NOW
=
datetime
.
now
(
UTC
)
NOW
=
datetime
.
now
(
UTC
)
DAY_DELTA
=
timedelta
(
days
=
1
)
DAY_DELTA
=
timedelta
(
days
=
1
)
YESTERDAY
=
NOW
-
DAY_DELTA
YESTERDAY
=
'yesterday'
TODAY
=
NOW
TODAY
=
'today'
TOMORROW
=
NOW
+
DAY_DELTA
TOMORROW
=
'tomorrow'
GRADER_TYPE
=
'Homework'
GRADER_TYPE
=
'Homework'
DATES
=
{
YESTERDAY
:
NOW
-
DAY_DELTA
,
TODAY
:
NOW
,
TOMORROW
:
NOW
+
DAY_DELTA
,
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
ProgressPageShowCorrectnessTests
,
self
)
.
setUp
()
super
(
ProgressPageShowCorrectnessTests
,
self
)
.
setUp
()
...
@@ -1853,12 +1864,12 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
...
@@ -1853,12 +1864,12 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
),
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
),
)
)
@ddt.unpack
@ddt.unpack
def
test_progress_page_no_problem_scores
(
self
,
show_correctness
,
due_date
,
graded
):
def
test_progress_page_no_problem_scores
(
self
,
show_correctness
,
due_date
_name
,
graded
):
"""
"""
Test that "no problem scores are present" for a course with no problems,
Test that "no problem scores are present" for a course with no problems,
regardless of the various show correctness settings.
regardless of the various show correctness settings.
"""
"""
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
due_date
,
graded
=
graded
)
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
self
.
DATES
[
due_date_name
]
,
graded
=
graded
)
resp
=
self
.
_get_progress_page
()
resp
=
self
.
_get_progress_page
()
# Test that no problem scores are present
# Test that no problem scores are present
...
@@ -1893,11 +1904,12 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
...
@@ -1893,11 +1904,12 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
,
False
),
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
,
False
),
)
)
@ddt.unpack
@ddt.unpack
def
test_progress_page_hide_scores_from_learner
(
self
,
show_correctness
,
due_date
,
graded
,
show_grades
):
def
test_progress_page_hide_scores_from_learner
(
self
,
show_correctness
,
due_date
_name
,
graded
,
show_grades
):
"""
"""
Test that problem scores are hidden on progress page when correctness is not available to the learner, and that
Test that problem scores are hidden on progress page when correctness is not available to the learner, and that
they are visible when it is.
they are visible when it is.
"""
"""
due_date
=
self
.
DATES
[
due_date_name
]
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
due_date
,
graded
=
graded
)
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
due_date
,
graded
=
graded
)
self
.
add_problem
()
self
.
add_problem
()
...
@@ -1944,10 +1956,11 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
...
@@ -1944,10 +1956,11 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
,
True
),
(
ShowCorrectness
.
PAST_DUE
,
TOMORROW
,
True
,
True
),
)
)
@ddt.unpack
@ddt.unpack
def
test_progress_page_hide_scores_from_staff
(
self
,
show_correctness
,
due_date
,
graded
,
show_grades
):
def
test_progress_page_hide_scores_from_staff
(
self
,
show_correctness
,
due_date
_name
,
graded
,
show_grades
):
"""
"""
Test that problem scores are hidden from staff viewing a learner's progress page only if show_correctness=never.
Test that problem scores are hidden from staff viewing a learner's progress page only if show_correctness=never.
"""
"""
due_date
=
self
.
DATES
[
due_date_name
]
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
due_date
,
graded
=
graded
)
self
.
setup_course
(
show_correctness
=
show_correctness
,
due_date
=
due_date
,
graded
=
graded
)
self
.
add_problem
()
self
.
add_problem
()
...
...
lms/djangoapps/grades/tests/test_scores.py
View file @
ae44f184
...
@@ -19,6 +19,35 @@ from xmodule.graders import ProblemScore
...
@@ -19,6 +19,35 @@ from xmodule.graders import ProblemScore
NOW
=
now
()
NOW
=
now
()
def
submission_value_repr
(
self
):
"""
String representation for the SubmissionValue namedtuple which excludes
the "created_at" attribute that changes with each execution. Needed for
consistency of ddt-generated test methods across pytest-xdist workers.
"""
return
'<SubmissionValue exists={}>'
.
format
(
self
.
exists
)
def
csm_value_repr
(
self
):
"""
String representation for the CSMValue namedtuple which excludes
the "created" attribute that changes with each execution. Needed for
consistency of ddt-generated test methods across pytest-xdist workers.
"""
return
'<CSMValue exists={} raw_earned={}>'
.
format
(
self
.
exists
,
self
.
raw_earned
)
def
expected_result_repr
(
self
):
"""
String representation for the ExpectedResult namedtuple which excludes
the "first_attempted" attribute that changes with each execution. Needed
for consistency of ddt-generated test methods across pytest-xdist workers.
"""
included
=
(
'raw_earned'
,
'raw_possible'
,
'weighted_earned'
,
'weighted_possible'
,
'weight'
,
'graded'
)
attributes
=
[
'{}={}'
.
format
(
name
,
getattr
(
self
,
name
))
for
name
in
included
]
return
'<ExpectedResult {}>'
.
format
(
' '
.
join
(
attributes
))
class
TestScoredBlockTypes
(
TestCase
):
class
TestScoredBlockTypes
(
TestCase
):
"""
"""
Tests for the possibly_scored function.
Tests for the possibly_scored function.
...
@@ -52,13 +81,16 @@ class TestGetScore(TestCase):
...
@@ -52,13 +81,16 @@ class TestGetScore(TestCase):
location
=
'test_location'
location
=
'test_location'
SubmissionValue
=
namedtuple
(
'SubmissionValue'
,
'exists, points_earned, points_possible, created_at'
)
SubmissionValue
=
namedtuple
(
'SubmissionValue'
,
'exists, points_earned, points_possible, created_at'
)
SubmissionValue
.
__repr__
=
submission_value_repr
CSMValue
=
namedtuple
(
'CSMValue'
,
'exists, raw_earned, raw_possible, created'
)
CSMValue
=
namedtuple
(
'CSMValue'
,
'exists, raw_earned, raw_possible, created'
)
CSMValue
.
__repr__
=
csm_value_repr
PersistedBlockValue
=
namedtuple
(
'PersistedBlockValue'
,
'exists, raw_possible, weight, graded'
)
PersistedBlockValue
=
namedtuple
(
'PersistedBlockValue'
,
'exists, raw_possible, weight, graded'
)
ContentBlockValue
=
namedtuple
(
'ContentBlockValue'
,
'raw_possible, weight, explicit_graded'
)
ContentBlockValue
=
namedtuple
(
'ContentBlockValue'
,
'raw_possible, weight, explicit_graded'
)
ExpectedResult
=
namedtuple
(
ExpectedResult
=
namedtuple
(
'ExpectedResult'
,
'ExpectedResult'
,
'raw_earned, raw_possible, weighted_earned, weighted_possible, weight, graded, first_attempted'
'raw_earned, raw_possible, weighted_earned, weighted_possible, weight, graded, first_attempted'
)
)
ExpectedResult
.
__repr__
=
expected_result_repr
def
_create_submissions_scores
(
self
,
submission_value
):
def
_create_submissions_scores
(
self
,
submission_value
):
"""
"""
...
...
lms/djangoapps/grades/tests/test_signals.py
View file @
ae44f184
...
@@ -16,7 +16,6 @@ from util.date_utils import to_timestamp
...
@@ -16,7 +16,6 @@ from util.date_utils import to_timestamp
from
..constants
import
ScoreDatabaseTableEnum
from
..constants
import
ScoreDatabaseTableEnum
from
..signals.handlers
import
(
from
..signals.handlers
import
(
disconnect_submissions_signal_receiver
,
disconnect_submissions_signal_receiver
,
enqueue_subsection_update
,
problem_raw_score_changed_handler
,
problem_raw_score_changed_handler
,
submissions_score_reset_handler
,
submissions_score_reset_handler
,
submissions_score_set_handler
submissions_score_set_handler
...
@@ -28,20 +27,30 @@ UUID_REGEX = re.compile(ur'%(hex)s{8}-%(hex)s{4}-%(hex)s{4}-%(hex)s{4}-%(hex)s{1
...
@@ -28,20 +27,30 @@ UUID_REGEX = re.compile(ur'%(hex)s{8}-%(hex)s{4}-%(hex)s{4}-%(hex)s{4}-%(hex)s{1
FROZEN_NOW_DATETIME
=
datetime
.
now
()
.
replace
(
tzinfo
=
pytz
.
UTC
)
FROZEN_NOW_DATETIME
=
datetime
.
now
()
.
replace
(
tzinfo
=
pytz
.
UTC
)
FROZEN_NOW_TIMESTAMP
=
to_timestamp
(
FROZEN_NOW_DATETIME
)
FROZEN_NOW_TIMESTAMP
=
to_timestamp
(
FROZEN_NOW_DATETIME
)
SUBMISSION_SET_KWARGS
=
{
SUBMISSIONS_SCORE_SET_HANDLER
=
'submissions_score_set_handler'
'points_possible'
:
10
,
SUBMISSIONS_SCORE_RESET_HANDLER
=
'submissions_score_reset_handler'
'points_earned'
:
5
,
HANDLERS
=
{
'anonymous_user_id'
:
'anonymous_id'
,
SUBMISSIONS_SCORE_SET_HANDLER
:
submissions_score_set_handler
,
'course_id'
:
'CourseID'
,
SUBMISSIONS_SCORE_RESET_HANDLER
:
submissions_score_reset_handler
,
'item_id'
:
'i4x://org/course/usage/123456'
,
'created_at'
:
FROZEN_NOW_TIMESTAMP
,
}
}
SUBMISSION_RESET_KWARGS
=
{
SUBMISSION_SET_KWARGS
=
'submission_set_kwargs'
'anonymous_user_id'
:
'anonymous_id'
,
SUBMISSION_RESET_KWARGS
=
'submission_reset_kwargs'
'course_id'
:
'CourseID'
,
SUBMISSION_KWARGS
=
{
'item_id'
:
'i4x://org/course/usage/123456'
,
SUBMISSION_SET_KWARGS
:
{
'created_at'
:
FROZEN_NOW_TIMESTAMP
,
'points_possible'
:
10
,
'points_earned'
:
5
,
'anonymous_user_id'
:
'anonymous_id'
,
'course_id'
:
'CourseID'
,
'item_id'
:
'i4x://org/course/usage/123456'
,
'created_at'
:
FROZEN_NOW_TIMESTAMP
,
},
SUBMISSION_RESET_KWARGS
:
{
'anonymous_user_id'
:
'anonymous_id'
,
'course_id'
:
'CourseID'
,
'item_id'
:
'i4x://org/course/usage/123456'
,
'created_at'
:
FROZEN_NOW_TIMESTAMP
,
},
}
}
PROBLEM_RAW_SCORE_CHANGED_KWARGS
=
{
PROBLEM_RAW_SCORE_CHANGED_KWARGS
=
{
...
@@ -82,6 +91,10 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -82,6 +91,10 @@ class ScoreChangedSignalRelayTest(TestCase):
This ensures that listeners in the LMS only have to handle one type
This ensures that listeners in the LMS only have to handle one type
of signal for all scoring events regardless of their origin.
of signal for all scoring events regardless of their origin.
"""
"""
SIGNALS
=
{
'score_set'
:
score_set
,
'score_reset'
:
score_reset
,
}
def
setUp
(
self
):
def
setUp
(
self
):
"""
"""
...
@@ -110,11 +123,11 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -110,11 +123,11 @@ class ScoreChangedSignalRelayTest(TestCase):
return
mock
return
mock
@ddt.data
(
@ddt.data
(
[
submissions_score_set_handler
,
SUBMISSION_SET_KWARGS
,
5
,
10
],
[
SUBMISSIONS_SCORE_SET_HANDLER
,
SUBMISSION_SET_KWARGS
,
5
,
10
],
[
submissions_score_reset_handler
,
SUBMISSION_RESET_KWARGS
,
0
,
0
],
[
SUBMISSIONS_SCORE_RESET_HANDLER
,
SUBMISSION_RESET_KWARGS
,
0
,
0
],
)
)
@ddt.unpack
@ddt.unpack
def
test_score_set_signal_handler
(
self
,
handler
,
kwargs
,
earned
,
possible
):
def
test_score_set_signal_handler
(
self
,
handler
_name
,
kwargs
,
earned
,
possible
):
"""
"""
Ensure that on receipt of a score_(re)set signal from the Submissions API,
Ensure that on receipt of a score_(re)set signal from the Submissions API,
the signal handler correctly converts it to a PROBLEM_WEIGHTED_SCORE_CHANGED
the signal handler correctly converts it to a PROBLEM_WEIGHTED_SCORE_CHANGED
...
@@ -122,7 +135,9 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -122,7 +135,9 @@ class ScoreChangedSignalRelayTest(TestCase):
Also ensures that the handler calls user_by_anonymous_id correctly.
Also ensures that the handler calls user_by_anonymous_id correctly.
"""
"""
handler
(
None
,
**
kwargs
)
local_kwargs
=
SUBMISSION_KWARGS
[
kwargs
]
.
copy
()
handler
=
HANDLERS
[
handler_name
]
handler
(
None
,
**
local_kwargs
)
expected_set_kwargs
=
{
expected_set_kwargs
=
{
'sender'
:
None
,
'sender'
:
None
,
'weighted_possible'
:
possible
,
'weighted_possible'
:
possible
,
...
@@ -134,35 +149,36 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -134,35 +149,36 @@ class ScoreChangedSignalRelayTest(TestCase):
'modified'
:
FROZEN_NOW_TIMESTAMP
,
'modified'
:
FROZEN_NOW_TIMESTAMP
,
'score_db_table'
:
'submissions'
,
'score_db_table'
:
'submissions'
,
}
}
if
handler
==
submissions_score_reset_handler
:
if
kwargs
==
SUBMISSION_RESET_KWARGS
:
expected_set_kwargs
[
'score_deleted'
]
=
True
expected_set_kwargs
[
'score_deleted'
]
=
True
self
.
signal_mock
.
assert_called_once_with
(
**
expected_set_kwargs
)
self
.
signal_mock
.
assert_called_once_with
(
**
expected_set_kwargs
)
self
.
get_user_mock
.
assert_called_once_with
(
kwargs
[
'anonymous_user_id'
])
self
.
get_user_mock
.
assert_called_once_with
(
local_
kwargs
[
'anonymous_user_id'
])
def
test_tnl_6599_zero_possible_bug
(
self
):
def
test_tnl_6599_zero_possible_bug
(
self
):
"""
"""
Ensure that, if coming from the submissions API, signals indicating a
Ensure that, if coming from the submissions API, signals indicating a
a possible score of 0 are swallowed for reasons outlined in TNL-6559.
a possible score of 0 are swallowed for reasons outlined in TNL-6559.
"""
"""
local_kwargs
=
SUBMISSION_
SET_KWARGS
.
copy
()
local_kwargs
=
SUBMISSION_
KWARGS
[
SUBMISSION_SET_KWARGS
]
.
copy
()
local_kwargs
[
'points_earned'
]
=
0
local_kwargs
[
'points_earned'
]
=
0
local_kwargs
[
'points_possible'
]
=
0
local_kwargs
[
'points_possible'
]
=
0
submissions_score_set_handler
(
None
,
**
local_kwargs
)
submissions_score_set_handler
(
None
,
**
local_kwargs
)
self
.
signal_mock
.
assert_not_called
()
self
.
signal_mock
.
assert_not_called
()
@ddt.data
(
@ddt.data
(
[
submissions_score_set_handler
,
SUBMISSION_SET_KWARGS
],
[
SUBMISSIONS_SCORE_SET_HANDLER
,
SUBMISSION_SET_KWARGS
],
[
submissions_score_reset_handler
,
SUBMISSION_RESET_KWARGS
]
[
SUBMISSIONS_SCORE_RESET_HANDLER
,
SUBMISSION_RESET_KWARGS
]
)
)
@ddt.unpack
@ddt.unpack
def
test_score_set_missing_kwarg
(
self
,
handler
,
kwargs
):
def
test_score_set_missing_kwarg
(
self
,
handler
_name
,
kwargs
):
"""
"""
Ensure that, on receipt of a score_(re)set signal from the Submissions API
Ensure that, on receipt of a score_(re)set signal from the Submissions API
that does not have the correct kwargs, the courseware model does not
that does not have the correct kwargs, the courseware model does not
generate a signal.
generate a signal.
"""
"""
for
missing
in
kwargs
:
handler
=
HANDLERS
[
handler_name
]
local_kwargs
=
kwargs
.
copy
()
for
missing
in
SUBMISSION_KWARGS
[
kwargs
]:
local_kwargs
=
SUBMISSION_KWARGS
[
kwargs
]
.
copy
()
del
local_kwargs
[
missing
]
del
local_kwargs
[
missing
]
with
self
.
assertRaises
(
KeyError
):
with
self
.
assertRaises
(
KeyError
):
...
@@ -170,18 +186,19 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -170,18 +186,19 @@ class ScoreChangedSignalRelayTest(TestCase):
self
.
signal_mock
.
assert_not_called
()
self
.
signal_mock
.
assert_not_called
()
@ddt.data
(
@ddt.data
(
[
submissions_score_set_handler
,
SUBMISSION_SET_KWARGS
],
[
SUBMISSIONS_SCORE_SET_HANDLER
,
SUBMISSION_SET_KWARGS
],
[
submissions_score_reset_handler
,
SUBMISSION_RESET_KWARGS
]
[
SUBMISSIONS_SCORE_RESET_HANDLER
,
SUBMISSION_RESET_KWARGS
]
)
)
@ddt.unpack
@ddt.unpack
def
test_score_set_bad_user
(
self
,
handler
,
kwargs
):
def
test_score_set_bad_user
(
self
,
handler
_name
,
kwargs
):
"""
"""
Ensure that, on receipt of a score_(re)set signal from the Submissions API
Ensure that, on receipt of a score_(re)set signal from the Submissions API
that has an invalid user ID, the courseware model does not generate a
that has an invalid user ID, the courseware model does not generate a
signal.
signal.
"""
"""
handler
=
HANDLERS
[
handler_name
]
self
.
get_user_mock
=
self
.
setup_patch
(
'lms.djangoapps.grades.signals.handlers.user_by_anonymous_id'
,
None
)
self
.
get_user_mock
=
self
.
setup_patch
(
'lms.djangoapps.grades.signals.handlers.user_by_anonymous_id'
,
None
)
handler
(
None
,
**
kwargs
)
handler
(
None
,
**
SUBMISSION_KWARGS
[
kwargs
]
)
self
.
signal_mock
.
assert_not_called
()
self
.
signal_mock
.
assert_not_called
()
def
test_raw_score_changed_signal_handler
(
self
):
def
test_raw_score_changed_signal_handler
(
self
):
...
@@ -198,14 +215,18 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -198,14 +215,18 @@ class ScoreChangedSignalRelayTest(TestCase):
self
.
signal_mock
.
assert_called_with
(
**
expected_set_kwargs
)
self
.
signal_mock
.
assert_called_with
(
**
expected_set_kwargs
)
@ddt.data
(
@ddt.data
(
[
score_set
,
'lms.djangoapps.grades.signals.handlers.submissions_score_set_handler'
,
SUBMISSION_SET_KWARGS
],
[
'score_set'
,
'lms.djangoapps.grades.signals.handlers.submissions_score_set_handler'
,
[
score_reset
,
'lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler'
,
SUBMISSION_RESET_KWARGS
]
SUBMISSION_SET_KWARGS
],
[
'score_reset'
,
'lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler'
,
SUBMISSION_RESET_KWARGS
]
)
)
@ddt.unpack
@ddt.unpack
def
test_disconnect_manager
(
self
,
signal
,
handler
,
kwargs
):
def
test_disconnect_manager
(
self
,
signal
_name
,
handler
,
kwargs
):
"""
"""
Tests to confirm the disconnect_submissions_signal_receiver context manager is working correctly.
Tests to confirm the disconnect_submissions_signal_receiver context manager is working correctly.
"""
"""
signal
=
self
.
SIGNALS
[
signal_name
]
kwargs
=
SUBMISSION_KWARGS
[
kwargs
]
.
copy
()
handler_mock
=
self
.
setup_patch
(
handler
,
None
)
handler_mock
=
self
.
setup_patch
(
handler
,
None
)
# Receiver connected before we start
# Receiver connected before we start
...
...
lms/djangoapps/instructor_task/tests/test_api.py
View file @
ae44f184
...
@@ -7,6 +7,7 @@ from nose.plugins.attrib import attr
...
@@ -7,6 +7,7 @@ from nose.plugins.attrib import attr
from
bulk_email.models
import
SEND_TO_LEARNERS
,
SEND_TO_MYSELF
,
SEND_TO_STAFF
,
CourseEmail
from
bulk_email.models
import
SEND_TO_LEARNERS
,
SEND_TO_MYSELF
,
SEND_TO_STAFF
,
CourseEmail
from
certificates.models
import
CertificateGenerationHistory
,
CertificateStatuses
from
certificates.models
import
CertificateGenerationHistory
,
CertificateStatuses
from
common.test.utils
import
normalize_repr
from
courseware.tests.factories
import
UserFactory
from
courseware.tests.factories
import
UserFactory
from
lms.djangoapps.instructor_task.api
import
(
from
lms.djangoapps.instructor_task.api
import
(
SpecificStudentIdMissingError
,
SpecificStudentIdMissingError
,
...
@@ -147,21 +148,29 @@ class InstructorTaskModuleSubmitTest(InstructorTaskModuleTestCase):
...
@@ -147,21 +148,29 @@ class InstructorTaskModuleSubmitTest(InstructorTaskModuleTestCase):
self
.
_test_submit_with_long_url
(
submit_delete_problem_state_for_all_students
)
self
.
_test_submit_with_long_url
(
submit_delete_problem_state_for_all_students
)
@ddt.data
(
@ddt.data
(
(
submit_rescore_problem_for_all_students
,
'rescore_problem'
),
(
normalize_repr
(
submit_rescore_problem_for_all_students
),
'rescore_problem'
),
(
submit_rescore_problem_for_all_students
,
'rescore_problem_if_higher'
,
{
'only_if_higher'
:
True
}),
(
submit_rescore_problem_for_student
,
'rescore_problem'
,
{
'student'
:
True
}),
(
submit_rescore_problem_for_student
,
'rescore_problem_if_higher'
,
{
'student'
:
True
,
'only_if_higher'
:
True
}),
(
submit_reset_problem_attempts_for_all_students
,
'reset_problem_attempts'
),
(
submit_delete_problem_state_for_all_students
,
'delete_problem_state'
),
(
submit_rescore_entrance_exam_for_student
,
'rescore_problem'
,
{
'student'
:
True
}),
(
(
submit_rescore_entrance_exam_for_student
,
normalize_repr
(
submit_rescore_problem_for_all_students
),
'rescore_problem_if_higher'
,
{
'only_if_higher'
:
True
}
),
(
normalize_repr
(
submit_rescore_problem_for_student
),
'rescore_problem'
,
{
'student'
:
True
}),
(
normalize_repr
(
submit_rescore_problem_for_student
),
'rescore_problem_if_higher'
,
{
'student'
:
True
,
'only_if_higher'
:
True
}
),
(
normalize_repr
(
submit_reset_problem_attempts_for_all_students
),
'reset_problem_attempts'
),
(
normalize_repr
(
submit_delete_problem_state_for_all_students
),
'delete_problem_state'
),
(
normalize_repr
(
submit_rescore_entrance_exam_for_student
),
'rescore_problem'
,
{
'student'
:
True
}),
(
normalize_repr
(
submit_rescore_entrance_exam_for_student
),
'rescore_problem_if_higher'
,
'rescore_problem_if_higher'
,
{
'student'
:
True
,
'only_if_higher'
:
True
},
{
'student'
:
True
,
'only_if_higher'
:
True
},
),
),
(
submit_reset_problem_attempts_in_entrance_exam
,
'reset_problem_attempts'
,
{
'student'
:
True
}),
(
normalize_repr
(
submit_reset_problem_attempts_in_entrance_exam
)
,
'reset_problem_attempts'
,
{
'student'
:
True
}),
(
submit_delete_entrance_exam_state_for_student
,
'delete_problem_state'
,
{
'student'
:
True
}),
(
normalize_repr
(
submit_delete_entrance_exam_state_for_student
)
,
'delete_problem_state'
,
{
'student'
:
True
}),
(
submit_override_score
,
'override_problem_score'
,
{
'student'
:
True
,
'score'
:
0
})
(
normalize_repr
(
submit_override_score
)
,
'override_problem_score'
,
{
'student'
:
True
,
'score'
:
0
})
)
)
@ddt.unpack
@ddt.unpack
def
test_submit_task
(
self
,
task_function
,
expected_task_type
,
params
=
None
):
def
test_submit_task
(
self
,
task_function
,
expected_task_type
,
params
=
None
):
...
...
lms/djangoapps/mobile_api/users/tests.py
View file @
ae44f184
...
@@ -84,6 +84,11 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
...
@@ -84,6 +84,11 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
LAST_WEEK
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
-
datetime
.
timedelta
(
days
=
7
)
LAST_WEEK
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
-
datetime
.
timedelta
(
days
=
7
)
ADVERTISED_START
=
"Spring 2016"
ADVERTISED_START
=
"Spring 2016"
ENABLED_SIGNALS
=
[
'course_published'
]
ENABLED_SIGNALS
=
[
'course_published'
]
DATES
=
{
'next_week'
:
NEXT_WEEK
,
'last_week'
:
LAST_WEEK
,
'default_start_date'
:
DEFAULT_START_DATE
,
}
@patch.dict
(
settings
.
FEATURES
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
@patch.dict
(
settings
.
FEATURES
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
,
*
args
,
**
kwargs
):
def
setUp
(
self
,
*
args
,
**
kwargs
):
...
@@ -175,12 +180,12 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
...
@@ -175,12 +180,12 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
self
.
assertFalse
(
result
[
'has_access'
])
self
.
assertFalse
(
result
[
'has_access'
])
@ddt.data
(
@ddt.data
(
(
NEXT_WEEK
,
ADVERTISED_START
,
ADVERTISED_START
,
"string"
),
(
'next_week'
,
ADVERTISED_START
,
ADVERTISED_START
,
"string"
),
(
NEXT_WEEK
,
None
,
defaultfilters
.
date
(
NEXT_WEEK
,
"DATE_FORMAT"
),
"timestamp"
),
(
'next_week'
,
None
,
defaultfilters
.
date
(
NEXT_WEEK
,
"DATE_FORMAT"
),
"timestamp"
),
(
NEXT_WEEK
,
''
,
defaultfilters
.
date
(
NEXT_WEEK
,
"DATE_FORMAT"
),
"timestamp"
),
(
'next_week'
,
''
,
defaultfilters
.
date
(
NEXT_WEEK
,
"DATE_FORMAT"
),
"timestamp"
),
(
DEFAULT_START_DATE
,
ADVERTISED_START
,
ADVERTISED_START
,
"string"
),
(
'default_start_date'
,
ADVERTISED_START
,
ADVERTISED_START
,
"string"
),
(
DEFAULT_START_DATE
,
''
,
None
,
"empty"
),
(
'default_start_date'
,
''
,
None
,
"empty"
),
(
DEFAULT_START_DATE
,
None
,
None
,
"empty"
),
(
'default_start_date'
,
None
,
None
,
"empty"
),
)
)
@ddt.unpack
@ddt.unpack
@patch.dict
(
settings
.
FEATURES
,
{
'DISABLE_START_DATES'
:
False
,
'ENABLE_MKTG_SITE'
:
True
})
@patch.dict
(
settings
.
FEATURES
,
{
'DISABLE_START_DATES'
:
False
,
'ENABLE_MKTG_SITE'
:
True
})
...
@@ -190,7 +195,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
...
@@ -190,7 +195,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
case the course has not started
case the course has not started
"""
"""
self
.
login
()
self
.
login
()
course
=
CourseFactory
.
create
(
start
=
s
tart
,
advertised_start
=
advertised_start
,
mobile_available
=
True
)
course
=
CourseFactory
.
create
(
start
=
s
elf
.
DATES
[
start
]
,
advertised_start
=
advertised_start
,
mobile_available
=
True
)
self
.
enroll
(
course
.
id
)
self
.
enroll
(
course
.
id
)
response
=
self
.
api_response
()
response
=
self
.
api_response
()
...
...
lms/djangoapps/teams/tests/test_models.py
View file @
ae44f184
...
@@ -118,17 +118,17 @@ class TeamMembershipTest(SharedModuleStoreTestCase):
...
@@ -118,17 +118,17 @@ class TeamMembershipTest(SharedModuleStoreTestCase):
class
TeamSignalsTest
(
EventTestMixin
,
SharedModuleStoreTestCase
):
class
TeamSignalsTest
(
EventTestMixin
,
SharedModuleStoreTestCase
):
"""Tests for handling of team-related signals."""
"""Tests for handling of team-related signals."""
SIGNALS
_LIST
=
(
SIGNALS
=
{
thread_created
,
'thread_created'
:
thread_created
,
thread_edited
,
'thread_edited'
:
thread_edited
,
thread_deleted
,
'thread_deleted'
:
thread_deleted
,
thread_voted
,
'thread_voted'
:
thread_voted
,
comment_created
,
'comment_created'
:
comment_created
,
comment_edited
,
'comment_edited'
:
comment_edited
,
comment_deleted
,
'comment_deleted'
:
comment_deleted
,
comment_voted
,
'comment_voted'
:
comment_voted
,
comment_endorsed
'comment_endorsed'
:
comment_endorsed
,
)
}
DISCUSSION_TOPIC_ID
=
'test_topic'
DISCUSSION_TOPIC_ID
=
'test_topic'
...
@@ -180,30 +180,33 @@ class TeamSignalsTest(EventTestMixin, SharedModuleStoreTestCase):
...
@@ -180,30 +180,33 @@ class TeamSignalsTest(EventTestMixin, SharedModuleStoreTestCase):
@ddt.data
(
@ddt.data
(
*
itertools
.
product
(
*
itertools
.
product
(
SIGNALS
_LIST
,
SIGNALS
.
keys
()
,
((
'user'
,
True
),
(
'moderator'
,
False
))
((
'user'
,
True
),
(
'moderator'
,
False
))
)
)
)
)
@ddt.unpack
@ddt.unpack
def
test_signals
(
self
,
signal
,
(
user
,
should_update
)):
def
test_signals
(
self
,
signal
_name
,
(
user
,
should_update
)):
"""Test that `last_activity_at` is correctly updated when team-related
"""Test that `last_activity_at` is correctly updated when team-related
signals are sent.
signals are sent.
"""
"""
with
self
.
assert_last_activity_updated
(
should_update
):
with
self
.
assert_last_activity_updated
(
should_update
):
user
=
getattr
(
self
,
user
)
user
=
getattr
(
self
,
user
)
signal
=
self
.
SIGNALS
[
signal_name
]
signal
.
send
(
sender
=
None
,
user
=
user
,
post
=
self
.
mock_comment
())
signal
.
send
(
sender
=
None
,
user
=
user
,
post
=
self
.
mock_comment
())
@ddt.data
(
thread_voted
,
comment_voted
)
@ddt.data
(
'thread_voted'
,
'comment_voted'
)
def
test_vote_others_post
(
self
,
signal
):
def
test_vote_others_post
(
self
,
signal
_name
):
"""Test that voting on another user's post correctly fires a
"""Test that voting on another user's post correctly fires a
signal."""
signal."""
with
self
.
assert_last_activity_updated
(
True
):
with
self
.
assert_last_activity_updated
(
True
):
signal
=
self
.
SIGNALS
[
signal_name
]
signal
.
send
(
sender
=
None
,
user
=
self
.
user
,
post
=
self
.
mock_comment
(
user
=
self
.
moderator
))
signal
.
send
(
sender
=
None
,
user
=
self
.
user
,
post
=
self
.
mock_comment
(
user
=
self
.
moderator
))
@ddt.data
(
*
SIGNALS
_LIST
)
@ddt.data
(
*
SIGNALS
.
keys
()
)
def
test_signals_course_context
(
self
,
signal
):
def
test_signals_course_context
(
self
,
signal
_name
):
"""Test that `last_activity_at` is not updated when activity takes
"""Test that `last_activity_at` is not updated when activity takes
place in discussions outside of a team.
place in discussions outside of a team.
"""
"""
with
self
.
assert_last_activity_updated
(
False
):
with
self
.
assert_last_activity_updated
(
False
):
signal
=
self
.
SIGNALS
[
signal_name
]
signal
.
send
(
sender
=
None
,
user
=
self
.
user
,
post
=
self
.
mock_comment
(
context
=
'course'
))
signal
.
send
(
sender
=
None
,
user
=
self
.
user
,
post
=
self
.
mock_comment
(
context
=
'course'
))
lms/djangoapps/verify_student/tests/test_views.py
View file @
ae44f184
...
@@ -89,8 +89,15 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
...
@@ -89,8 +89,15 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
PASSWORD
=
"test_password"
PASSWORD
=
"test_password"
NOW
=
datetime
.
now
(
pytz
.
UTC
)
NOW
=
datetime
.
now
(
pytz
.
UTC
)
YESTERDAY
=
NOW
-
timedelta
(
days
=
1
)
YESTERDAY
=
'yesterday'
TOMORROW
=
NOW
+
timedelta
(
days
=
1
)
TOMORROW
=
'tomorrow'
NEXT_YEAR
=
'next_year'
DATES
=
{
YESTERDAY
:
NOW
-
timedelta
(
days
=
1
),
TOMORROW
:
NOW
+
timedelta
(
days
=
1
),
NEXT_YEAR
:
NOW
+
timedelta
(
days
=
360
),
None
:
None
,
}
URLCONF_MODULES
=
[
'openedx.core.djangoapps.embargo'
]
URLCONF_MODULES
=
[
'openedx.core.djangoapps.embargo'
]
...
@@ -492,7 +499,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
...
@@ -492,7 +499,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
)
)
@ddt.unpack
@ddt.unpack
def
test_payment_confirmation_course_details
(
self
,
course_start
,
show_courseware_url
):
def
test_payment_confirmation_course_details
(
self
,
course_start
,
show_courseware_url
):
course
=
self
.
_create_course
(
"verified"
,
course_start
=
course_start
)
course
=
self
.
_create_course
(
"verified"
,
course_start
=
self
.
DATES
[
course_start
]
)
self
.
_enroll
(
course
.
id
,
"verified"
)
self
.
_enroll
(
course
.
id
,
"verified"
)
response
=
self
.
_get_page
(
'verify_student_payment_confirmation'
,
course
.
id
)
response
=
self
.
_get_page
(
'verify_student_payment_confirmation'
,
course
.
id
)
...
@@ -753,9 +760,10 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
...
@@ -753,9 +760,10 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
self
.
assertContains
(
response
,
"verification deadline"
)
self
.
assertContains
(
response
,
"verification deadline"
)
self
.
assertContains
(
response
,
deadline
)
self
.
assertContains
(
response
,
deadline
)
@ddt.data
(
datetime
.
now
(
tz
=
pytz
.
UTC
)
+
timedelta
(
days
=
360
)
,
None
)
@ddt.data
(
NEXT_YEAR
,
None
)
def
test_course_mode_expired_verification_deadline_in_future
(
self
,
verification_deadline
):
def
test_course_mode_expired_verification_deadline_in_future
(
self
,
verification_deadline
):
"""Verify that student can not upgrade in expired course mode."""
"""Verify that student can not upgrade in expired course mode."""
verification_deadline
=
self
.
DATES
[
verification_deadline
]
course_modes
=
(
"verified"
,
"credit"
)
course_modes
=
(
"verified"
,
"credit"
)
course
=
self
.
_create_course
(
*
course_modes
)
course
=
self
.
_create_course
(
*
course_modes
)
...
...
openedx/core/djangoapps/content/block_structure/tests/helpers.py
View file @
ae44f184
...
@@ -183,6 +183,9 @@ class MockTransformer(BlockStructureTransformer):
...
@@ -183,6 +183,9 @@ class MockTransformer(BlockStructureTransformer):
def
transform
(
self
,
usage_info
,
block_structure
):
def
transform
(
self
,
usage_info
,
block_structure
):
pass
pass
def
__repr__
(
self
):
return
self
.
name
()
class
MockFilteringTransformer
(
FilteringTransformerMixin
,
BlockStructureTransformer
):
class
MockFilteringTransformer
(
FilteringTransformerMixin
,
BlockStructureTransformer
):
"""
"""
...
...
openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py
View file @
ae44f184
...
@@ -46,10 +46,18 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
...
@@ -46,10 +46,18 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
"""
"""
TODAY
=
timezone
.
now
()
TODAY
=
timezone
.
now
()
LAST_MONTH
=
TODAY
-
datetime
.
timedelta
(
days
=
30
)
LAST_MONTH
=
'last_month'
LAST_WEEK
=
TODAY
-
datetime
.
timedelta
(
days
=
7
)
LAST_WEEK
=
'last_week'
NEXT_WEEK
=
TODAY
+
datetime
.
timedelta
(
days
=
7
)
NEXT_WEEK
=
'next_week'
NEXT_MONTH
=
TODAY
+
datetime
.
timedelta
(
days
=
30
)
NEXT_MONTH
=
'next_month'
DATES
=
{
'default_start_date'
:
DEFAULT_START_DATE
,
LAST_MONTH
:
TODAY
-
datetime
.
timedelta
(
days
=
30
),
LAST_WEEK
:
TODAY
-
datetime
.
timedelta
(
days
=
7
),
NEXT_WEEK
:
TODAY
+
datetime
.
timedelta
(
days
=
7
),
NEXT_MONTH
:
TODAY
+
datetime
.
timedelta
(
days
=
30
),
None
:
None
,
}
COURSE_OVERVIEW_TABS
=
{
'courseware'
,
'info'
,
'textbooks'
,
'discussion'
,
'wiki'
,
'progress'
}
COURSE_OVERVIEW_TABS
=
{
'courseware'
,
'info'
,
'textbooks'
,
'discussion'
,
'wiki'
,
'progress'
}
...
@@ -229,7 +237,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
...
@@ -229,7 +237,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
},
},
{
{
# # Don't set display name
# # Don't set display name
"start"
:
DEFAULT_START_DATE
,
# Default start and end dates
"start"
:
'default_start_date'
,
# Default start and end dates
"end"
:
None
,
"end"
:
None
,
"advertised_start"
:
None
,
# No advertised start
"advertised_start"
:
None
,
# No advertised start
"pre_requisite_courses"
:
[],
# No pre-requisites
"pre_requisite_courses"
:
[],
# No pre-requisites
...
@@ -251,10 +259,15 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
...
@@ -251,10 +259,15 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
modulestore_type (ModuleStoreEnum.Type): type of store to create the
modulestore_type (ModuleStoreEnum.Type): type of store to create the
course in.
course in.
"""
"""
kwargs
=
course_kwargs
.
copy
()
kwargs
[
'start'
]
=
self
.
DATES
[
course_kwargs
[
'start'
]]
kwargs
[
'end'
]
=
self
.
DATES
[
course_kwargs
[
'end'
]]
if
'announcement'
in
course_kwargs
:
kwargs
[
'announcement'
]
=
self
.
DATES
[
course_kwargs
[
'announcement'
]]
# Note: We specify a value for 'run' here because, for some reason,
# Note: We specify a value for 'run' here because, for some reason,
# .create raises an InvalidKeyError if we don't (even though my
# .create raises an InvalidKeyError if we don't (even though my
# other test functions don't specify a run but work fine).
# other test functions don't specify a run but work fine).
course
=
CourseFactory
.
create
(
default_store
=
modulestore_type
,
run
=
"TestRun"
,
**
course_
kwargs
)
course
=
CourseFactory
.
create
(
default_store
=
modulestore_type
,
run
=
"TestRun"
,
**
kwargs
)
self
.
check_course_overview_against_course
(
course
)
self
.
check_course_overview_against_course
(
course
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
...
...
openedx/core/djangoapps/credit/tests/test_signals.py
View file @
ae44f184
...
@@ -35,6 +35,12 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
...
@@ -35,6 +35,12 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
VALID_DUE_DATE
=
datetime
.
now
(
pytz
.
UTC
)
+
timedelta
(
days
=
20
)
VALID_DUE_DATE
=
datetime
.
now
(
pytz
.
UTC
)
+
timedelta
(
days
=
20
)
EXPIRED_DUE_DATE
=
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
20
)
EXPIRED_DUE_DATE
=
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
20
)
DATES
=
{
'valid'
:
VALID_DUE_DATE
,
'expired'
:
EXPIRED_DUE_DATE
,
None
:
None
,
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestMinGradedRequirementStatus
,
self
)
.
setUp
()
super
(
TestMinGradedRequirementStatus
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
self
.
course
=
CourseFactory
.
create
(
...
@@ -85,13 +91,13 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
...
@@ -85,13 +91,13 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
self
.
assertEqual
(
req_status
[
0
][
'reason'
],
expected_reason
)
self
.
assertEqual
(
req_status
[
0
][
'reason'
],
expected_reason
)
@ddt.data
(
@ddt.data
(
(
0.6
,
VALID_DUE_DATE
),
(
0.6
,
'valid'
),
(
0.52
,
None
),
(
0.52
,
None
),
)
)
@ddt.unpack
@ddt.unpack
def
test_min_grade_requirement_with_valid_grade
(
self
,
grade
,
due_date
):
def
test_min_grade_requirement_with_valid_grade
(
self
,
grade
,
due_date
_name
):
"""Test with valid grades submitted before deadline"""
"""Test with valid grades submitted before deadline"""
self
.
assert_requirement_status
(
grade
,
due_date
,
'satisfied'
)
self
.
assert_requirement_status
(
grade
,
self
.
DATES
[
due_date_name
]
,
'satisfied'
)
def
test_grade_changed
(
self
):
def
test_grade_changed
(
self
):
""" Verify successive calls to update a satisfied grade requirement are recorded. """
""" Verify successive calls to update a satisfied grade requirement are recorded. """
...
@@ -106,12 +112,12 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
...
@@ -106,12 +112,12 @@ class TestMinGradedRequirementStatus(ModuleStoreTestCase):
@ddt.data
(
@ddt.data
(
(
0.50
,
None
),
(
0.50
,
None
),
(
0.51
,
None
),
(
0.51
,
None
),
(
0.40
,
VALID_DUE_DATE
),
(
0.40
,
'valid'
),
)
)
@ddt.unpack
@ddt.unpack
def
test_min_grade_requirement_failed_grade_valid_deadline
(
self
,
grade
,
due_date
):
def
test_min_grade_requirement_failed_grade_valid_deadline
(
self
,
grade
,
due_date
_name
):
"""Test with failed grades and deadline is still open or not defined."""
"""Test with failed grades and deadline is still open or not defined."""
self
.
assert_requirement_status
(
grade
,
due_date
,
None
)
self
.
assert_requirement_status
(
grade
,
self
.
DATES
[
due_date_name
]
,
None
)
def
test_min_grade_requirement_failed_grade_expired_deadline
(
self
):
def
test_min_grade_requirement_failed_grade_expired_deadline
(
self
):
"""Test with failed grades and deadline expire"""
"""Test with failed grades and deadline expire"""
...
...
openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py
View file @
ae44f184
...
@@ -29,6 +29,10 @@ COMMAND_MODULE = 'openedx.core.djangoapps.programs.management.commands.backpopul
...
@@ -29,6 +29,10 @@ COMMAND_MODULE = 'openedx.core.djangoapps.programs.management.commands.backpopul
class
BackpopulateProgramCredentialsTests
(
CatalogIntegrationMixin
,
CredentialsApiConfigMixin
,
TestCase
):
class
BackpopulateProgramCredentialsTests
(
CatalogIntegrationMixin
,
CredentialsApiConfigMixin
,
TestCase
):
"""Tests for the backpopulate_program_credentials management command."""
"""Tests for the backpopulate_program_credentials management command."""
course_run_key
,
alternate_course_run_key
=
(
generate_course_run_key
()
for
__
in
range
(
2
))
course_run_key
,
alternate_course_run_key
=
(
generate_course_run_key
()
for
__
in
range
(
2
))
# Constants for the _get_programs_data hierarchy types used in test_flatten()
SEPARATE_PROGRAMS
=
'separate_programs'
SEPARATE_COURSES
=
'separate_courses'
SAME_COURSE
=
'same_course'
def
setUp
(
self
):
def
setUp
(
self
):
super
(
BackpopulateProgramCredentialsTests
,
self
)
.
setUp
()
super
(
BackpopulateProgramCredentialsTests
,
self
)
.
setUp
()
...
@@ -44,6 +48,54 @@ class BackpopulateProgramCredentialsTests(CatalogIntegrationMixin, CredentialsAp
...
@@ -44,6 +48,54 @@ class BackpopulateProgramCredentialsTests(CatalogIntegrationMixin, CredentialsAp
catalog_integration
=
self
.
create_catalog_integration
()
catalog_integration
=
self
.
create_catalog_integration
()
UserFactory
(
username
=
catalog_integration
.
service_username
)
UserFactory
(
username
=
catalog_integration
.
service_username
)
def
_get_programs_data
(
self
,
hierarchy_type
):
"""
Generate a mock response for get_programs() with the given type of
course hierarchy. Dramatically simplifies (and makes consistent
between test runs) the ddt-generated test_flatten methods.
"""
if
hierarchy_type
==
self
.
SEPARATE_PROGRAMS
:
return
[
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
self
.
course_run_key
),
]),
]
),
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
self
.
alternate_course_run_key
),
]),
]
),
]
elif
hierarchy_type
==
self
.
SEPARATE_COURSES
:
return
[
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
self
.
course_run_key
),
]),
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
self
.
alternate_course_run_key
),
]),
]
),
]
else
:
# SAME_COURSE
return
[
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
self
.
course_run_key
),
CourseRunFactory
(
key
=
self
.
alternate_course_run_key
),
]),
]
),
]
@ddt.data
(
True
,
False
)
@ddt.data
(
True
,
False
)
def
test_handle
(
self
,
commit
,
mock_task
,
mock_get_programs
):
def
test_handle
(
self
,
commit
,
mock_task
,
mock_get_programs
):
"""
"""
...
@@ -112,49 +164,10 @@ class BackpopulateProgramCredentialsTests(CatalogIntegrationMixin, CredentialsAp
...
@@ -112,49 +164,10 @@ class BackpopulateProgramCredentialsTests(CatalogIntegrationMixin, CredentialsAp
# The task should be called for both users since professional and no-id-professional are equivalent.
# The task should be called for both users since professional and no-id-professional are equivalent.
mock_task
.
assert_has_calls
([
mock
.
call
(
self
.
alice
.
username
),
mock
.
call
(
self
.
bob
.
username
)])
mock_task
.
assert_has_calls
([
mock
.
call
(
self
.
alice
.
username
),
mock
.
call
(
self
.
bob
.
username
)])
@ddt.data
(
@ddt.data
(
SEPARATE_PROGRAMS
,
SEPARATE_COURSES
,
SAME_COURSE
)
[
def
test_handle_flatten
(
self
,
hierarchy_type
,
mock_task
,
mock_get_programs
):
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
course_run_key
),
]),
]
),
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
alternate_course_run_key
),
]),
]
),
],
[
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
course_run_key
),
]),
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
alternate_course_run_key
),
]),
]
),
],
[
ProgramFactory
(
courses
=
[
CourseFactory
(
course_runs
=
[
CourseRunFactory
(
key
=
course_run_key
),
CourseRunFactory
(
key
=
alternate_course_run_key
),
]),
]
),
],
)
def
test_handle_flatten
(
self
,
data
,
mock_task
,
mock_get_programs
):
"""Verify that program structures are flattened correctly."""
"""Verify that program structures are flattened correctly."""
mock_get_programs
.
return_value
=
data
mock_get_programs
.
return_value
=
self
.
_get_programs_data
(
hierarchy_type
)
GeneratedCertificateFactory
(
GeneratedCertificateFactory
(
user
=
self
.
alice
,
user
=
self
.
alice
,
...
...
openedx/core/djangoapps/user_api/validation/tests/test_views.py
View file @
ae44f184
...
@@ -53,11 +53,11 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
...
@@ -53,11 +53,11 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
)
)
@ddt.data
(
@ddt.data
(
[
'name'
,
(
name
for
name
in
testutils
.
VALID_NAMES
)
],
[
'name'
,
[
name
for
name
in
testutils
.
VALID_NAMES
]
],
[
'email'
,
(
email
for
email
in
testutils
.
VALID_EMAILS
)
],
[
'email'
,
[
email
for
email
in
testutils
.
VALID_EMAILS
]
],
[
'password'
,
(
password
for
password
in
testutils
.
VALID_PASSWORDS
)
],
[
'password'
,
[
password
for
password
in
testutils
.
VALID_PASSWORDS
]
],
[
'username'
,
(
username
for
username
in
testutils
.
VALID_USERNAMES
)
],
[
'username'
,
[
username
for
username
in
testutils
.
VALID_USERNAMES
]
],
[
'country'
,
(
country
for
country
in
testutils
.
VALID_COUNTRIES
)
]
[
'country'
,
[
country
for
country
in
testutils
.
VALID_COUNTRIES
]
]
)
)
@ddt.unpack
@ddt.unpack
def
test_positive_validation_decision
(
self
,
form_field_name
,
user_data
):
def
test_positive_validation_decision
(
self
,
form_field_name
,
user_data
):
...
@@ -71,11 +71,11 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
...
@@ -71,11 +71,11 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
@ddt.data
(
@ddt.data
(
# Skip None type for invalidity checks.
# Skip None type for invalidity checks.
[
'name'
,
(
name
for
name
in
testutils
.
INVALID_NAMES
[
1
:])
],
[
'name'
,
[
name
for
name
in
testutils
.
INVALID_NAMES
[
1
:]]
],
[
'email'
,
(
email
for
email
in
testutils
.
INVALID_EMAILS
[
1
:])
],
[
'email'
,
[
email
for
email
in
testutils
.
INVALID_EMAILS
[
1
:]]
],
[
'password'
,
(
password
for
password
in
testutils
.
INVALID_PASSWORDS
[
1
:])
],
[
'password'
,
[
password
for
password
in
testutils
.
INVALID_PASSWORDS
[
1
:]]
],
[
'username'
,
(
username
for
username
in
testutils
.
INVALID_USERNAMES
[
1
:])
],
[
'username'
,
[
username
for
username
in
testutils
.
INVALID_USERNAMES
[
1
:]]
],
[
'country'
,
(
country
for
country
in
testutils
.
INVALID_COUNTRIES
[
1
:])
]
[
'country'
,
[
country
for
country
in
testutils
.
INVALID_COUNTRIES
[
1
:]]
]
)
)
@ddt.unpack
@ddt.unpack
def
test_negative_validation_decision
(
self
,
form_field_name
,
user_data
):
def
test_negative_validation_decision
(
self
,
form_field_name
,
user_data
):
...
...
openedx/core/djangoapps/util/tests/test_user_messages.py
View file @
ae44f184
...
@@ -6,6 +6,8 @@ import ddt
...
@@ -6,6 +6,8 @@ import ddt
from
django.contrib.messages.middleware
import
MessageMiddleware
from
django.contrib.messages.middleware
import
MessageMiddleware
from
django.test
import
RequestFactory
,
TestCase
from
django.test
import
RequestFactory
,
TestCase
from
common.test.utils
import
normalize_repr
from
openedx.core.djangolib.markup
import
HTML
,
Text
from
openedx.core.djangolib.markup
import
HTML
,
Text
from
student.tests.factories
import
UserFactory
from
student.tests.factories
import
UserFactory
...
@@ -60,10 +62,10 @@ class UserMessagesTestCase(TestCase):
...
@@ -60,10 +62,10 @@ class UserMessagesTestCase(TestCase):
self
.
assertEquals
(
messages
[
0
]
.
icon_class
,
expected_icon_class
)
self
.
assertEquals
(
messages
[
0
]
.
icon_class
,
expected_icon_class
)
@ddt.data
(
@ddt.data
(
(
PageLevelMessages
.
register_error_message
,
UserMessageType
.
ERROR
),
(
normalize_repr
(
PageLevelMessages
.
register_error_message
)
,
UserMessageType
.
ERROR
),
(
PageLevelMessages
.
register_info_message
,
UserMessageType
.
INFO
),
(
normalize_repr
(
PageLevelMessages
.
register_info_message
)
,
UserMessageType
.
INFO
),
(
PageLevelMessages
.
register_success_message
,
UserMessageType
.
SUCCESS
),
(
normalize_repr
(
PageLevelMessages
.
register_success_message
)
,
UserMessageType
.
SUCCESS
),
(
PageLevelMessages
.
register_warning_message
,
UserMessageType
.
WARNING
),
(
normalize_repr
(
PageLevelMessages
.
register_warning_message
)
,
UserMessageType
.
WARNING
),
)
)
@ddt.unpack
@ddt.unpack
def
test_message_type
(
self
,
register_message_function
,
expected_message_type
):
def
test_message_type
(
self
,
register_message_function
,
expected_message_type
):
...
...
openedx/core/lib/xblock_builtin/xblock_discussion/tests.py
View file @
ae44f184
...
@@ -16,7 +16,16 @@ from xblock.fields import ScopeIds, UNIQUE_ID, NO_CACHE_VALUE
...
@@ -16,7 +16,16 @@ from xblock.fields import ScopeIds, UNIQUE_ID, NO_CACHE_VALUE
from
xblock.runtime
import
Runtime
from
xblock.runtime
import
Runtime
def
attribute_pair_repr
(
self
):
"""
Custom string representation for the AttributePair namedtuple which is
consistent between test runs.
"""
return
'<AttributePair name={}>'
.
format
(
self
.
name
)
AttributePair
=
namedtuple
(
"AttributePair"
,
[
"name"
,
"value"
])
AttributePair
=
namedtuple
(
"AttributePair"
,
[
"name"
,
"value"
])
AttributePair
.
__repr__
=
attribute_pair_repr
ID_ATTR_NAMES
=
(
"discussion_id"
,
"id"
,)
ID_ATTR_NAMES
=
(
"discussion_id"
,
"id"
,)
...
...
openedx/features/course_experience/tests/views/test_course_outline.py
View file @
ae44f184
...
@@ -20,8 +20,6 @@ from xmodule.course_module import DEFAULT_START_DATE
...
@@ -20,8 +20,6 @@ from xmodule.course_module import DEFAULT_START_DATE
from
.test_course_home
import
course_home_url
from
.test_course_home
import
course_home_url
TEST_PASSWORD
=
'test'
TEST_PASSWORD
=
'test'
FUTURE_DAY
=
datetime
.
datetime
.
now
()
+
datetime
.
timedelta
(
days
=
30
)
PAST_DAY
=
datetime
.
datetime
.
now
()
-
datetime
.
timedelta
(
days
=
30
)
class
TestCourseOutlinePage
(
SharedModuleStoreTestCase
):
class
TestCourseOutlinePage
(
SharedModuleStoreTestCase
):
...
@@ -343,14 +341,22 @@ class TestEmptyCourseOutlinePage(SharedModuleStoreTestCase):
...
@@ -343,14 +341,22 @@ class TestEmptyCourseOutlinePage(SharedModuleStoreTestCase):
"""
"""
Test the new course outline view.
Test the new course outline view.
"""
"""
FUTURE_DAY
=
'future_day'
PAST_DAY
=
'past_day'
DATES
=
{
'default_start_date'
:
DEFAULT_START_DATE
,
FUTURE_DAY
:
datetime
.
datetime
.
now
()
+
datetime
.
timedelta
(
days
=
30
),
PAST_DAY
:
datetime
.
datetime
.
now
()
-
datetime
.
timedelta
(
days
=
30
),
}
@ddt.data
(
@ddt.data
(
(
FUTURE_DAY
,
'This course has not started yet, and will launch on'
),
(
FUTURE_DAY
,
'This course has not started yet, and will launch on'
),
(
PAST_DAY
,
"We're still working on course content."
),
(
PAST_DAY
,
"We're still working on course content."
),
(
DEFAULT_START_DATE
,
'This course has not started yet.'
),
(
'default_start_date'
,
'This course has not started yet.'
),
)
)
@ddt.unpack
@ddt.unpack
def
test_empty_course_rendering
(
self
,
start_date
,
expected_text
):
def
test_empty_course_rendering
(
self
,
start_date
_name
,
expected_text
):
course
=
CourseFactory
.
create
(
start
=
s
tart_date
)
course
=
CourseFactory
.
create
(
start
=
s
elf
.
DATES
[
start_date_name
]
)
test_user
=
UserFactory
(
password
=
TEST_PASSWORD
)
test_user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
test_user
,
course
.
id
)
CourseEnrollment
.
enroll
(
test_user
,
course
.
id
)
self
.
client
.
login
(
username
=
test_user
.
username
,
password
=
TEST_PASSWORD
)
self
.
client
.
login
(
username
=
test_user
.
username
,
password
=
TEST_PASSWORD
)
...
...
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