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
7d0b72a4
Commit
7d0b72a4
authored
Jun 27, 2013
by
jnater
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #204 from edx/jnater/courseware_tests
Jnater/courseware tests
parents
be4d5f32
af05d05c
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
803 additions
and
923 deletions
+803
-923
common/lib/xmodule/xmodule/modulestore/__init__.py
+2
-2
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
+34
-18
common/lib/xmodule/xmodule/modulestore/tests/factories.py
+11
-1
lms/djangoapps/courseware/access.py
+0
-1
lms/djangoapps/courseware/tests/helpers.py
+134
-0
lms/djangoapps/courseware/tests/modulestore_config.py
+72
-0
lms/djangoapps/courseware/tests/test_draft_modulestore.py
+21
-0
lms/djangoapps/courseware/tests/test_masquerade.py
+5
-4
lms/djangoapps/courseware/tests/test_navigation.py
+100
-0
lms/djangoapps/courseware/tests/test_view_authentication.py
+374
-0
lms/djangoapps/courseware/tests/tests.py
+28
-880
lms/djangoapps/instructor/tests/test_download_csv.py
+5
-4
lms/djangoapps/instructor/tests/test_enrollment.py
+2
-1
lms/djangoapps/instructor/tests/test_forum_admin.py
+4
-3
lms/djangoapps/open_ended_grading/tests.py
+10
-8
lms/urls.py
+1
-1
No files found.
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
7d0b72a4
...
@@ -52,8 +52,8 @@ class Location(_LocationBase):
...
@@ -52,8 +52,8 @@ class Location(_LocationBase):
Locations representations of URLs of the
Locations representations of URLs of the
form {tag}://{org}/{course}/{category}/{name}[@{revision}]
form {tag}://{org}/{course}/{category}/{name}[@{revision}]
However, they can also be represented a dictionaries (specifying each component),
However, they can also be represented a
s
dictionaries (specifying each component),
tuples or list (specified in order), or as strings of the url
tuples or list
s
(specified in order), or as strings of the url
'''
'''
__slots__
=
()
__slots__
=
()
...
...
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
View file @
7d0b72a4
...
@@ -15,10 +15,26 @@ class ModuleStoreTestCase(TestCase):
...
@@ -15,10 +15,26 @@ class ModuleStoreTestCase(TestCase):
and drops it they are finished. """
and drops it they are finished. """
@staticmethod
@staticmethod
def
update_course
(
course
,
data
):
"""
Updates the version of course in the modulestore
with the metadata in 'data' and returns the updated version.
'course' is an instance of CourseDescriptor for which we want
to update metadata.
'data' is a dictionary with an entry for each CourseField we want to update.
"""
store
=
xmodule
.
modulestore
.
django
.
modulestore
()
store
.
update_metadata
(
course
.
location
,
data
)
updated_course
=
store
.
get_instance
(
course
.
id
,
course
.
location
)
return
updated_course
@staticmethod
def
flush_mongo_except_templates
():
def
flush_mongo_except_templates
():
'''
"""
Delete everything in the module store except templates
Delete everything in the module store except templates
.
'''
"""
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
()
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
()
# This query means: every item in the collection
# This query means: every item in the collection
...
@@ -31,11 +47,11 @@ class ModuleStoreTestCase(TestCase):
...
@@ -31,11 +47,11 @@ class ModuleStoreTestCase(TestCase):
@staticmethod
@staticmethod
def
load_templates_if_necessary
():
def
load_templates_if_necessary
():
'''
"""
Load templates into the direct modulestore only if they do not already exist.
Load templates into the direct modulestore only if they do not already exist.
We need the templates, because they are copied to create
We need the templates, because they are copied to create
XModules such as sections and problems
XModules such as sections and problems
.
'''
"""
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
(
'direct'
)
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
(
'direct'
)
# Count the number of templates
# Count the number of templates
...
@@ -47,9 +63,9 @@ class ModuleStoreTestCase(TestCase):
...
@@ -47,9 +63,9 @@ class ModuleStoreTestCase(TestCase):
@classmethod
@classmethod
def
setUpClass
(
cls
):
def
setUpClass
(
cls
):
'''
"""
Flush the mongo store and set up templates
Flush the mongo store and set up templates
.
'''
"""
# Use a uuid to differentiate
# Use a uuid to differentiate
# the mongo collections on jenkins.
# the mongo collections on jenkins.
...
@@ -67,9 +83,9 @@ class ModuleStoreTestCase(TestCase):
...
@@ -67,9 +83,9 @@ class ModuleStoreTestCase(TestCase):
@classmethod
@classmethod
def
tearDownClass
(
cls
):
def
tearDownClass
(
cls
):
'''
"""
Revert to the old modulestore settings
Revert to the old modulestore settings
.
'''
"""
# Clean up by dropping the collection
# Clean up by dropping the collection
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
()
modulestore
=
xmodule
.
modulestore
.
django
.
modulestore
()
...
@@ -81,9 +97,9 @@ class ModuleStoreTestCase(TestCase):
...
@@ -81,9 +97,9 @@ class ModuleStoreTestCase(TestCase):
settings
.
MODULESTORE
=
cls
.
orig_modulestore
settings
.
MODULESTORE
=
cls
.
orig_modulestore
def
_pre_setup
(
self
):
def
_pre_setup
(
self
):
'''
"""
Remove everything but the templates before each test
Remove everything but the templates before each test
.
'''
"""
# Flush anything that is not a template
# Flush anything that is not a template
ModuleStoreTestCase
.
flush_mongo_except_templates
()
ModuleStoreTestCase
.
flush_mongo_except_templates
()
...
@@ -95,9 +111,9 @@ class ModuleStoreTestCase(TestCase):
...
@@ -95,9 +111,9 @@ class ModuleStoreTestCase(TestCase):
super
(
ModuleStoreTestCase
,
self
)
.
_pre_setup
()
super
(
ModuleStoreTestCase
,
self
)
.
_pre_setup
()
def
_post_teardown
(
self
):
def
_post_teardown
(
self
):
'''
"""
Flush everything we created except the templates
Flush everything we created except the templates
.
'''
"""
# Flush anything that is not a template
# Flush anything that is not a template
ModuleStoreTestCase
.
flush_mongo_except_templates
()
ModuleStoreTestCase
.
flush_mongo_except_templates
()
...
...
common/lib/xmodule/xmodule/modulestore/tests/factories.py
View file @
7d0b72a4
from
factory
import
Factory
,
lazy_attribute_sequence
,
lazy_attribute
from
factory
import
Factory
,
lazy_attribute_sequence
,
lazy_attribute
from
uuid
import
uuid4
from
uuid
import
uuid4
import
datetime
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.x_module
import
ModuleSystem
from
xmodule.x_module
import
ModuleSystem
from
mitxmako.shortcuts
import
render_to_string
from
mitxmako.shortcuts
import
render_to_string
from
xblock.runtime
import
InvalidScopeError
from
xblock.runtime
import
InvalidScopeError
import
datetime
from
pytz
import
UTC
from
pytz
import
UTC
...
@@ -59,6 +60,10 @@ class XModuleCourseFactory(Factory):
...
@@ -59,6 +60,10 @@ class XModuleCourseFactory(Factory):
if
data
is
not
None
:
if
data
is
not
None
:
store
.
update_item
(
new_course
.
location
,
data
)
store
.
update_item
(
new_course
.
location
,
data
)
# update_item updates the the course as it exists in the modulestore, but doesn't
# update the instance we are working with, so have to refetch the course after updating it.
new_course
=
store
.
get_instance
(
new_course
.
id
,
new_course
.
location
)
return
new_course
return
new_course
...
@@ -147,6 +152,10 @@ class XModuleItemFactory(Factory):
...
@@ -147,6 +152,10 @@ class XModuleItemFactory(Factory):
if
new_item
.
location
.
category
not
in
DETACHED_CATEGORIES
:
if
new_item
.
location
.
category
not
in
DETACHED_CATEGORIES
:
store
.
update_children
(
parent_location
,
parent
.
children
+
[
new_item
.
location
.
url
()])
store
.
update_children
(
parent_location
,
parent
.
children
+
[
new_item
.
location
.
url
()])
# update_children updates the the item as it exists in the modulestore, but doesn't
# update the instance we are working with, so have to refetch the item after updating it.
new_item
=
store
.
get_item
(
new_item
.
location
)
return
new_item
return
new_item
...
@@ -181,6 +190,7 @@ def get_test_xmodule_for_descriptor(descriptor):
...
@@ -181,6 +190,7 @@ def get_test_xmodule_for_descriptor(descriptor):
)
)
return
descriptor
.
xmodule
(
module_sys
)
return
descriptor
.
xmodule
(
module_sys
)
def
_test_xblock_model_data_accessor
(
descriptor
):
def
_test_xblock_model_data_accessor
(
descriptor
):
simple_map
=
{}
simple_map
=
{}
for
field
in
descriptor
.
fields
:
for
field
in
descriptor
.
fields
:
...
...
lms/djangoapps/courseware/access.py
View file @
7d0b72a4
...
@@ -586,7 +586,6 @@ def _has_access_to_location(user, location, access_level, course_context):
...
@@ -586,7 +586,6 @@ def _has_access_to_location(user, location, access_level, course_context):
debug
(
"Deny: user not in groups
%
s"
,
instructor_groups
)
debug
(
"Deny: user not in groups
%
s"
,
instructor_groups
)
else
:
else
:
log
.
debug
(
"Error in access._has_access_to_location access_level=
%
s unknown"
%
access_level
)
log
.
debug
(
"Error in access._has_access_to_location access_level=
%
s unknown"
%
access_level
)
return
False
return
False
...
...
lms/djangoapps/courseware/tests/helpers.py
0 → 100644
View file @
7d0b72a4
import
json
from
django.contrib.auth.models
import
User
from
django.core.urlresolvers
import
reverse
from
student.models
import
Registration
from
django.test
import
TestCase
def
check_for_get_code
(
self
,
code
,
url
):
"""
Check that we got the expected code when accessing url via GET.
Returns the HTTP response.
`self` is a class that subclasses TestCase.
`code` is a status code for HTTP responses.
`url` is a url pattern for which we have to test the response.
"""
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
code
,
"got code
%
d for url '
%
s'. Expected code
%
d"
%
(
resp
.
status_code
,
url
,
code
))
return
resp
def
check_for_post_code
(
self
,
code
,
url
,
data
=
{}):
"""
Check that we got the expected code when accessing url via POST.
Returns the HTTP response.
`self` is a class that subclasses TestCase.
`code` is a status code for HTTP responses.
`url` is a url pattern for which we want to test the response.
"""
resp
=
self
.
client
.
post
(
url
,
data
)
self
.
assertEqual
(
resp
.
status_code
,
code
,
"got code
%
d for url '
%
s'. Expected code
%
d"
%
(
resp
.
status_code
,
url
,
code
))
return
resp
class
LoginEnrollmentTestCase
(
TestCase
):
"""
Provides support for user creation,
activation, login, and course enrollment.
"""
def
setup_user
(
self
):
"""
Create a user account, activate, and log in.
"""
self
.
email
=
'foo@test.com'
self
.
password
=
'bar'
self
.
username
=
'test'
self
.
create_account
(
self
.
username
,
self
.
email
,
self
.
password
)
self
.
activate_user
(
self
.
email
)
self
.
login
(
self
.
email
,
self
.
password
)
# ============ User creation and login ==============
def
login
(
self
,
email
,
password
):
"""
Login, check that the corresponding view's response has a 200 status code.
"""
resp
=
self
.
client
.
post
(
reverse
(
'login'
),
{
'email'
:
email
,
'password'
:
password
})
self
.
assertEqual
(
resp
.
status_code
,
200
)
data
=
json
.
loads
(
resp
.
content
)
self
.
assertTrue
(
data
[
'success'
])
def
logout
(
self
):
"""
Logout; check that the HTTP response code indicates redirection
as expected.
"""
# should redirect
check_for_get_code
(
self
,
302
,
reverse
(
'logout'
))
def
create_account
(
self
,
username
,
email
,
password
):
"""
Create the account and check that it worked.
"""
resp
=
check_for_post_code
(
self
,
200
,
reverse
(
'create_account'
),
{
'username'
:
username
,
'email'
:
email
,
'password'
:
password
,
'name'
:
'username'
,
'terms_of_service'
:
'true'
,
'honor_code'
:
'true'
,
})
data
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
data
[
'success'
],
True
)
# Check both that the user is created, and inactive
self
.
assertFalse
(
User
.
objects
.
get
(
email
=
email
)
.
is_active
)
def
activate_user
(
self
,
email
):
"""
Look up the activation key for the user, then hit the activate view.
No error checking.
"""
activation_key
=
Registration
.
objects
.
get
(
user__email
=
email
)
.
activation_key
# and now we try to activate
check_for_get_code
(
self
,
200
,
reverse
(
'activate'
,
kwargs
=
{
'key'
:
activation_key
}))
# Now make sure that the user is now actually activated
self
.
assertTrue
(
User
.
objects
.
get
(
email
=
email
)
.
is_active
)
def
enroll
(
self
,
course
,
verify
=
False
):
"""
Try to enroll and return boolean indicating result.
`course` is an instance of CourseDescriptor.
`verify` is an optional boolean parameter specifying whether we
want to verify that the student was successfully enrolled
in the course.
"""
resp
=
self
.
client
.
post
(
reverse
(
'change_enrollment'
),
{
'enrollment_action'
:
'enroll'
,
'course_id'
:
course
.
id
,
})
result
=
resp
.
status_code
==
200
if
verify
:
self
.
assertTrue
(
result
)
return
result
def
unenroll
(
self
,
course
):
"""
Unenroll the currently logged-in user, and check that it worked.
`course` is an instance of CourseDescriptor.
"""
check_for_post_code
(
self
,
200
,
reverse
(
'change_enrollment'
),
{
'enrollment_action'
:
'unenroll'
,
'course_id'
:
course
.
id
})
lms/djangoapps/courseware/tests/modulestore_config.py
0 → 100644
View file @
7d0b72a4
from
uuid
import
uuid4
from
django.conf
import
settings
def
mongo_store_config
(
data_dir
):
"""
Defines default module store using MongoModuleStore.
Use of this config requires mongo to be running.
"""
store
=
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
'OPTIONS'
:
{
'default_class'
:
'xmodule.raw_module.RawDescriptor'
,
'host'
:
'localhost'
,
'db'
:
'test_xmodule'
,
'collection'
:
'modulestore'
,
'fs_root'
:
data_dir
,
'render_template'
:
'mitxmako.shortcuts.render_to_string'
}
}
}
store
[
'direct'
]
=
store
[
'default'
]
return
store
def
draft_mongo_store_config
(
data_dir
):
"""
Defines default module store using DraftMongoModuleStore.
"""
modulestore_options
=
{
'default_class'
:
'xmodule.raw_module.RawDescriptor'
,
'host'
:
'localhost'
,
'db'
:
'xmodule'
,
'collection'
:
'modulestore_
%
s'
%
uuid4
()
.
hex
,
'fs_root'
:
data_dir
,
'render_template'
:
'mitxmako.shortcuts.render_to_string'
}
return
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.DraftMongoModuleStore'
,
'OPTIONS'
:
modulestore_options
},
'direct'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
'OPTIONS'
:
modulestore_options
}
}
def
xml_store_config
(
data_dir
):
"""
Defines default module store using XMLModuleStore.
"""
return
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
'OPTIONS'
:
{
'data_dir'
:
data_dir
,
'default_class'
:
'xmodule.hidden_module.HiddenDescriptor'
,
}
}
}
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
TEST_DATA_XML_MODULESTORE
=
xml_store_config
(
TEST_DATA_DIR
)
TEST_DATA_MONGO_MODULESTORE
=
mongo_store_config
(
TEST_DATA_DIR
)
TEST_DATA_DRAFT_MONGO_MODULESTORE
=
draft_mongo_store_config
(
TEST_DATA_DIR
)
lms/djangoapps/courseware/tests/test_draft_modulestore.py
0 → 100644
View file @
7d0b72a4
from
django.test
import
TestCase
from
django.test.utils
import
override_settings
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
Location
from
modulestore_config
import
TEST_DATA_DRAFT_MONGO_MODULESTORE
@override_settings
(
MODULESTORE
=
TEST_DATA_DRAFT_MONGO_MODULESTORE
)
class
TestDraftModuleStore
(
TestCase
):
def
test_get_items_with_course_items
(
self
):
store
=
modulestore
()
# fix was to allow get_items() to take the course_id parameter
store
.
get_items
(
Location
(
None
,
None
,
'vertical'
,
None
,
None
),
course_id
=
'abc'
,
depth
=
0
)
# test success is just getting through the above statement.
# The bug was that 'course_id' argument was
# not allowed to be passed in (i.e. was throwing exception)
lms/djangoapps/courseware/tests/test_masquerade.py
View file @
7d0b72a4
...
@@ -12,13 +12,15 @@ from django.test.utils import override_settings
...
@@ -12,13 +12,15 @@ from django.test.utils import override_settings
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
,
User
from
courseware.access
import
_course_staff_group_name
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_XML_MODULESTORE
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
import
xmodule.modulestore.django
import
xmodule.modulestore.django
import
json
import
json
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestStaffMasqueradeAsStudent
(
LoginEnrollmentTestCase
):
class
TestStaffMasqueradeAsStudent
(
LoginEnrollmentTestCase
):
'''
'''
...
@@ -41,7 +43,7 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase):
...
@@ -41,7 +43,7 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase):
def
make_instructor
(
course
):
def
make_instructor
(
course
):
group_name
=
_course_staff_group_name
(
course
.
location
)
group_name
=
_course_staff_group_name
(
course
.
location
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
.
user_set
.
add
(
get_user
(
self
.
instructor
))
g
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
self
.
instructor
))
make_instructor
(
self
.
graded_course
)
make_instructor
(
self
.
graded_course
)
...
@@ -67,7 +69,6 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase):
...
@@ -67,7 +69,6 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase):
self
.
assertTrue
(
sdebug
in
resp
.
content
)
self
.
assertTrue
(
sdebug
in
resp
.
content
)
def
toggle_masquerade
(
self
):
def
toggle_masquerade
(
self
):
'''
'''
Toggle masquerade state
Toggle masquerade state
...
...
lms/djangoapps/courseware/tests/test_navigation.py
0 → 100644
View file @
7d0b72a4
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
helpers
import
LoginEnrollmentTestCase
,
check_for_get_code
from
modulestore_config
import
TEST_DATA_MONGO_MODULESTORE
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestNavigation
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
"""
Check that navigation state is saved properly.
"""
STUDENT_INFO
=
[(
'view@test.com'
,
'foo'
),
(
'view2@test.com'
,
'foo'
)]
def
setUp
(
self
):
self
.
test_course
=
CourseFactory
.
create
(
display_name
=
'Robot_Sub_Course'
)
self
.
course
=
CourseFactory
.
create
(
display_name
=
'Robot_Super_Course'
)
self
.
chapter0
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'Overview'
)
self
.
chapter9
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'factory_chapter'
)
self
.
section0
=
ItemFactory
.
create
(
parent_location
=
self
.
chapter0
.
location
,
display_name
=
'Welcome'
)
self
.
section9
=
ItemFactory
.
create
(
parent_location
=
self
.
chapter9
.
location
,
display_name
=
'factory_section'
)
# Create student accounts and activate them.
for
i
in
range
(
len
(
self
.
STUDENT_INFO
)):
email
,
password
=
self
.
STUDENT_INFO
[
i
]
username
=
'u{0}'
.
format
(
i
)
self
.
create_account
(
username
,
email
,
password
)
self
.
activate_user
(
email
)
def
test_redirects_first_time
(
self
):
"""
Verify that the first time we click on the courseware tab we are
redirected to the 'Welcome' section.
"""
email
,
password
=
self
.
STUDENT_INFO
[
0
]
self
.
login
(
email
,
password
)
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirects
(
resp
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
def
test_redirects_second_time
(
self
):
"""
Verify the accordion remembers we've already visited the Welcome section
and redirects correpondingly.
"""
email
,
password
=
self
.
STUDENT_INFO
[
0
]
self
.
login
(
email
,
password
)
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
self
.
client
.
get
(
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirects
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
}))
def
test_accordion_state
(
self
):
"""
Verify the accordion remembers which chapter you were last viewing.
"""
email
,
password
=
self
.
STUDENT_INFO
[
0
]
self
.
login
(
email
,
password
)
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
# Now we directly navigate to a section in a chapter other than 'Overview'.
check_for_get_code
(
self
,
200
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'factory_chapter'
,
'section'
:
'factory_section'
}))
# And now hitting the courseware tab should redirect to 'factory_chapter'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirects
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'factory_chapter'
}))
lms/djangoapps/courseware/tests/test_view_authentication.py
0 → 100644
View file @
7d0b72a4
import
datetime
import
pytz
from
mock
import
patch
from
django.contrib.auth.models
import
User
,
Group
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
# Need access to internal func to put users in the right group
from
courseware.access
import
(
has_access
,
_course_staff_group_name
,
course_beta_test_group_name
,
settings
as
access_settings
)
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
helpers
import
LoginEnrollmentTestCase
,
check_for_get_code
from
modulestore_config
import
TEST_DATA_MONGO_MODULESTORE
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestViewAuth
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
"""
Check that view authentication works properly.
"""
ACCOUNT_INFO
=
[(
'view@test.com'
,
'foo'
),
(
'view2@test.com'
,
'foo'
)]
@staticmethod
def
_reverse_urls
(
names
,
course
):
"""
Reverse a list of course urls.
`names` is a list of URL names that correspond to sections in a course.
`course` is the instance of CourseDescriptor whose section URLs are to be returned.
Returns a list URLs corresponding to section in the passed in course.
"""
return
[
reverse
(
name
,
kwargs
=
{
'course_id'
:
course
.
id
})
for
name
in
names
]
def
_check_non_staff_light
(
self
,
course
):
"""
Check that non-staff have access to light urls.
`course` is an instance of CourseDescriptor.
"""
urls
=
[
reverse
(
'about_course'
,
kwargs
=
{
'course_id'
:
course
.
id
}),
reverse
(
'courses'
)]
for
url
in
urls
:
check_for_get_code
(
self
,
200
,
url
)
def
_check_non_staff_dark
(
self
,
course
):
"""
Check that non-staff don't have access to dark urls.
"""
names
=
[
'courseware'
,
'instructor_dashboard'
,
'progress'
]
urls
=
self
.
_reverse_urls
(
names
,
course
)
urls
.
extend
([
reverse
(
'book'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'book_index'
:
index
})
for
index
,
book
in
enumerate
(
course
.
textbooks
)
])
for
url
in
urls
:
check_for_get_code
(
self
,
404
,
url
)
def
_check_staff
(
self
,
course
):
"""
Check that access is right for staff in course.
"""
names
=
[
'about_course'
,
'instructor_dashboard'
,
'progress'
]
urls
=
self
.
_reverse_urls
(
names
,
course
)
urls
.
extend
([
reverse
(
'book'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'book_index'
:
index
})
for
index
,
book
in
enumerate
(
course
.
textbooks
)
])
for
url
in
urls
:
check_for_get_code
(
self
,
200
,
url
)
# The student progress tab is not accessible to a student
# before launch, so the instructor view-as-student feature
# should return a 404 as well.
# TODO (vshnayder): If this is not the behavior we want, will need
# to make access checking smarter and understand both the effective
# user (the student), and the requesting user (the prof)
url
=
reverse
(
'student_progress'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'student_id'
:
User
.
objects
.
get
(
email
=
self
.
ACCOUNT_INFO
[
0
][
0
])
.
id
})
check_for_get_code
(
self
,
404
,
url
)
# The courseware url should redirect, not 200
url
=
self
.
_reverse_urls
([
'courseware'
],
course
)[
0
]
check_for_get_code
(
self
,
302
,
url
)
def
setUp
(
self
):
self
.
course
=
CourseFactory
.
create
(
number
=
'999'
,
display_name
=
'Robot_Super_Course'
)
self
.
overview_chapter
=
ItemFactory
.
create
(
display_name
=
'Overview'
)
self
.
courseware_chapter
=
ItemFactory
.
create
(
display_name
=
'courseware'
)
self
.
test_course
=
CourseFactory
.
create
(
number
=
'666'
,
display_name
=
'Robot_Sub_Course'
)
self
.
sub_courseware_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
test_course
.
location
,
display_name
=
'courseware'
)
self
.
sub_overview_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
sub_courseware_chapter
.
location
,
display_name
=
'Overview'
)
self
.
welcome_section
=
ItemFactory
.
create
(
parent_location
=
self
.
overview_chapter
.
location
,
display_name
=
'Welcome'
)
# Create two accounts and activate them.
for
i
in
range
(
len
(
self
.
ACCOUNT_INFO
)):
username
,
email
,
password
=
'u{0}'
.
format
(
i
),
self
.
ACCOUNT_INFO
[
i
][
0
],
self
.
ACCOUNT_INFO
[
i
][
1
]
self
.
create_account
(
username
,
email
,
password
)
self
.
activate_user
(
email
)
def
test_redirection_unenrolled
(
self
):
"""
Verify unenrolled student is redirected to the 'about' section of the chapter
instead of the 'Welcome' section after clicking on the courseware tab.
"""
email
,
password
=
self
.
ACCOUNT_INFO
[
0
]
self
.
login
(
email
,
password
)
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirects
(
response
,
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
]))
def
test_redirection_enrolled
(
self
):
"""
Verify enrolled student is redirected to the 'Welcome' section of
the chapter after clicking on the courseware tab.
"""
email
,
password
=
self
.
ACCOUNT_INFO
[
0
]
self
.
login
(
email
,
password
)
self
.
enroll
(
self
.
course
)
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirects
(
response
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
def
test_instructor_page_access_nonstaff
(
self
):
"""
Verify non-staff cannot load the instructor
dashboard, the grade views, and student profile pages.
"""
email
,
password
=
self
.
ACCOUNT_INFO
[
0
]
self
.
login
(
email
,
password
)
self
.
enroll
(
self
.
course
)
self
.
enroll
(
self
.
test_course
)
urls
=
[
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}),
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
test_course
.
id
})]
# Shouldn't be able to get to the instructor pages
for
url
in
urls
:
check_for_get_code
(
self
,
404
,
url
)
def
test_instructor_course_access
(
self
):
"""
Verify instructor can load the instructor dashboard, the grade views,
and student profile pages for their course.
"""
email
,
password
=
self
.
ACCOUNT_INFO
[
1
]
# Make the instructor staff in self.course
group_name
=
_course_staff_group_name
(
self
.
course
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
email
))
self
.
login
(
email
,
password
)
# Now should be able to get to self.course, but not self.test_course
url
=
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
})
check_for_get_code
(
self
,
200
,
url
)
url
=
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
test_course
.
id
})
check_for_get_code
(
self
,
404
,
url
)
def
test_instructor_as_staff_access
(
self
):
"""
Verify the instructor can load staff pages if he is given
staff permissions.
"""
email
,
password
=
self
.
ACCOUNT_INFO
[
1
]
self
.
login
(
email
,
password
)
# now make the instructor also staff
instructor
=
User
.
objects
.
get
(
email
=
email
)
instructor
.
is_staff
=
True
instructor
.
save
()
# and now should be able to load both
urls
=
[
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}),
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
self
.
test_course
.
id
})]
for
url
in
urls
:
check_for_get_code
(
self
,
200
,
url
)
@patch.dict
(
access_settings
.
MITX_FEATURES
,
{
'DISABLE_START_DATES'
:
False
})
def
test_dark_launch_enrolled_student
(
self
):
"""
Make sure that before course start, students can't access course
pages.
"""
student_email
,
student_password
=
self
.
ACCOUNT_INFO
[
0
]
# Make courses start in the future
now
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
course_data
=
{
'start'
:
tomorrow
}
test_course_data
=
{
'start'
:
tomorrow
}
self
.
course
=
self
.
update_course
(
self
.
course
,
course_data
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
test_course_data
)
self
.
assertFalse
(
self
.
course
.
has_started
())
self
.
assertFalse
(
self
.
test_course
.
has_started
())
# First, try with an enrolled student
self
.
login
(
student_email
,
student_password
)
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
# shouldn't be able to get to anything except the light pages
self
.
_check_non_staff_light
(
self
.
course
)
self
.
_check_non_staff_dark
(
self
.
course
)
self
.
_check_non_staff_light
(
self
.
test_course
)
self
.
_check_non_staff_dark
(
self
.
test_course
)
@patch.dict
(
access_settings
.
MITX_FEATURES
,
{
'DISABLE_START_DATES'
:
False
})
def
test_dark_launch_instructor
(
self
):
"""
Make sure that before course start instructors can access the
page for their course.
"""
instructor_email
,
instructor_password
=
self
.
ACCOUNT_INFO
[
1
]
now
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
course_data
=
{
'start'
:
tomorrow
}
test_course_data
=
{
'start'
:
tomorrow
}
self
.
course
=
self
.
update_course
(
self
.
course
,
course_data
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
test_course_data
)
# Make the instructor staff in self.course
group_name
=
_course_staff_group_name
(
self
.
course
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
instructor_email
))
self
.
logout
()
self
.
login
(
instructor_email
,
instructor_password
)
# Enroll in the classes---can't see courseware otherwise.
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
# should now be able to get to everything for self.course
self
.
_check_non_staff_light
(
self
.
test_course
)
self
.
_check_non_staff_dark
(
self
.
test_course
)
self
.
_check_staff
(
self
.
course
)
@patch.dict
(
access_settings
.
MITX_FEATURES
,
{
'DISABLE_START_DATES'
:
False
})
def
test_dark_launch_staff
(
self
):
"""
Make sure that before course start staff can access
course pages.
"""
instructor_email
,
instructor_password
=
self
.
ACCOUNT_INFO
[
1
]
now
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
course_data
=
{
'start'
:
tomorrow
}
test_course_data
=
{
'start'
:
tomorrow
}
self
.
course
=
self
.
update_course
(
self
.
course
,
course_data
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
test_course_data
)
self
.
login
(
instructor_email
,
instructor_password
)
self
.
enroll
(
self
.
course
,
True
)
self
.
enroll
(
self
.
test_course
,
True
)
# now also make the instructor staff
instructor
=
User
.
objects
.
get
(
email
=
instructor_email
)
instructor
.
is_staff
=
True
instructor
.
save
()
# and now should be able to load both
self
.
_check_staff
(
self
.
course
)
self
.
_check_staff
(
self
.
test_course
)
@patch.dict
(
access_settings
.
MITX_FEATURES
,
{
'DISABLE_START_DATES'
:
False
})
def
test_enrollment_period
(
self
):
"""
Check that enrollment periods work.
"""
student_email
,
student_password
=
self
.
ACCOUNT_INFO
[
0
]
instructor_email
,
instructor_password
=
self
.
ACCOUNT_INFO
[
1
]
# Make courses start in the future
now
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
nextday
=
tomorrow
+
datetime
.
timedelta
(
days
=
1
)
yesterday
=
now
-
datetime
.
timedelta
(
days
=
1
)
course_data
=
{
'enrollment_start'
:
tomorrow
,
'enrollment_end'
:
nextday
}
test_course_data
=
{
'enrollment_start'
:
yesterday
,
'enrollment_end'
:
tomorrow
}
# self.course's enrollment period hasn't started
self
.
course
=
self
.
update_course
(
self
.
course
,
course_data
)
# test_course course's has
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
test_course_data
)
# First, try with an enrolled student
self
.
login
(
student_email
,
student_password
)
self
.
assertFalse
(
self
.
enroll
(
self
.
course
))
self
.
assertTrue
(
self
.
enroll
(
self
.
test_course
))
# Make the instructor staff in the self.course
group_name
=
_course_staff_group_name
(
self
.
course
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
instructor_email
))
self
.
logout
()
self
.
login
(
instructor_email
,
instructor_password
)
self
.
assertTrue
(
self
.
enroll
(
self
.
course
))
# now make the instructor global staff, but not in the instructor group
group
.
user_set
.
remove
(
User
.
objects
.
get
(
email
=
instructor_email
))
instructor
=
User
.
objects
.
get
(
email
=
instructor_email
)
instructor
.
is_staff
=
True
instructor
.
save
()
# unenroll and try again
self
.
unenroll
(
self
.
course
)
self
.
assertTrue
(
self
.
enroll
(
self
.
course
))
@patch.dict
(
access_settings
.
MITX_FEATURES
,
{
'DISABLE_START_DATES'
:
False
})
def
test_beta_period
(
self
):
"""
Check that beta-test access works.
"""
student_email
,
student_password
=
self
.
ACCOUNT_INFO
[
0
]
instructor_email
,
instructor_password
=
self
.
ACCOUNT_INFO
[
1
]
# Make courses start in the future
now
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
course_data
=
{
'start'
:
tomorrow
}
# self.course's hasn't started
self
.
course
=
self
.
update_course
(
self
.
course
,
course_data
)
self
.
assertFalse
(
self
.
course
.
has_started
())
# but should be accessible for beta testers
self
.
course
.
lms
.
days_early_for_beta
=
2
# student user shouldn't see it
student_user
=
User
.
objects
.
get
(
email
=
student_email
)
self
.
assertFalse
(
has_access
(
student_user
,
self
.
course
,
'load'
))
# now add the student to the beta test group
group_name
=
course_beta_test_group_name
(
self
.
course
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
student_user
)
# now the student should see it
self
.
assertTrue
(
has_access
(
student_user
,
self
.
course
,
'load'
))
lms/djangoapps/courseware/tests/tests.py
View file @
7d0b72a4
'''
'''
Test for lms courseware app
Test for lms courseware app
'''
'''
import
logging
import
json
import
random
import
random
from
urlparse
import
urlsplit
,
urlunsplit
from
uuid
import
uuid4
from
django.contrib.auth.models
import
User
,
Group
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.test.client
import
RequestFactory
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
import
xmodule.modulestore.django
import
xmodule.modulestore.django
# Need access to internal func to put users in the right group
from
courseware
import
grades
from
courseware.model_data
import
ModelDataCache
from
courseware.access
import
(
has_access
,
_course_staff_group_name
,
course_beta_test_group_name
)
from
student.models
import
Registration
from
xmodule.error_module
import
ErrorDescriptor
from
xmodule.error_module
import
ErrorDescriptor
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
xmodule.modulestore.xml
import
XMLModuleStore
from
xmodule.modulestore.xml
import
XMLModuleStore
import
datetime
from
django.utils.timezone
import
UTC
log
=
logging
.
getLogger
(
"mitx."
+
__name__
)
def
parse_json
(
response
):
"""Parse response, which is assumed to be json"""
return
json
.
loads
(
response
.
content
)
def
get_user
(
email
):
'''look up a user by email'''
return
User
.
objects
.
get
(
email
=
email
)
def
get_registration
(
email
):
'''look up registration object by email'''
return
Registration
.
objects
.
get
(
user__email
=
email
)
def
mongo_store_config
(
data_dir
):
'''
Defines default module store using MongoModuleStore
Use of this config requires mongo to be running
'''
store
=
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
'OPTIONS'
:
{
'default_class'
:
'xmodule.raw_module.RawDescriptor'
,
'host'
:
'localhost'
,
'db'
:
'test_xmodule'
,
'collection'
:
'modulestore_
%
s'
%
uuid4
()
.
hex
,
'fs_root'
:
data_dir
,
'render_template'
:
'mitxmako.shortcuts.render_to_string'
,
}
}
}
store
[
'direct'
]
=
store
[
'default'
]
return
store
def
draft_mongo_store_config
(
data_dir
):
'''Defines default module store using DraftMongoModuleStore'''
return
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.DraftMongoModuleStore'
,
'OPTIONS'
:
{
'default_class'
:
'xmodule.raw_module.RawDescriptor'
,
'host'
:
'localhost'
,
'db'
:
'test_xmodule'
,
'collection'
:
'modulestore_
%
s'
%
uuid4
()
.
hex
,
'fs_root'
:
data_dir
,
'render_template'
:
'mitxmako.shortcuts.render_to_string'
,
}
},
'direct'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
'OPTIONS'
:
{
'default_class'
:
'xmodule.raw_module.RawDescriptor'
,
'host'
:
'localhost'
,
'db'
:
'test_xmodule'
,
'collection'
:
'modulestore_
%
s'
%
uuid4
()
.
hex
,
'fs_root'
:
data_dir
,
'render_template'
:
'mitxmako.shortcuts.render_to_string'
,
}
}
}
def
xml_store_config
(
data_dir
):
'''Defines default module store using XMLModuleStore'''
return
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
'OPTIONS'
:
{
'data_dir'
:
data_dir
,
'default_class'
:
'xmodule.hidden_module.HiddenDescriptor'
,
}
}
}
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
TEST_DATA_XML_MODULESTORE
=
xml_store_config
(
TEST_DATA_DIR
)
TEST_DATA_MONGO_MODULESTORE
=
mongo_store_config
(
TEST_DATA_DIR
)
TEST_DATA_DRAFT_MONGO_MODULESTORE
=
draft_mongo_store_config
(
TEST_DATA_DIR
)
class
LoginEnrollmentTestCase
(
TestCase
):
'''
Base TestCase providing support for user creation,
activation, login, and course enrollment
'''
def
assertRedirectsNoFollow
(
self
,
response
,
expected_url
):
"""
http://devblog.point2.com/2010/04/23/djangos-assertredirects-little-gotcha/
Don't check that the redirected-to page loads--there should be other tests for that.
Some of the code taken from django.test.testcases.py
"""
self
.
assertEqual
(
response
.
status_code
,
302
,
'Response status code was
%
d instead of 302'
%
(
response
.
status_code
))
url
=
response
[
'Location'
]
e_scheme
,
e_netloc
,
e_path
,
e_query
,
e_fragment
=
urlsplit
(
expected_url
)
if
not
(
e_scheme
or
e_netloc
):
expected_url
=
urlunsplit
((
'http'
,
'testserver'
,
e_path
,
e_query
,
e_fragment
))
self
.
assertEqual
(
url
,
expected_url
,
"Response redirected to '
%
s', expected '
%
s'"
%
(
url
,
expected_url
))
def
setup_viewtest_user
(
self
):
from
helpers
import
LoginEnrollmentTestCase
'''create a user account, activate, and log in'''
from
modulestore_config
import
TEST_DATA_DIR
,
TEST_DATA_XML_MODULESTORE
,
TEST_DATA_MONGO_MODULESTORE
,
TEST_DATA_DRAFT_MONGO_MODULESTORE
self
.
viewtest_email
=
'view@test.com'
self
.
viewtest_password
=
'foo'
self
.
viewtest_username
=
'viewtest'
self
.
create_account
(
self
.
viewtest_username
,
self
.
viewtest_email
,
self
.
viewtest_password
)
self
.
activate_user
(
self
.
viewtest_email
)
self
.
login
(
self
.
viewtest_email
,
self
.
viewtest_password
)
# ============ User creation and login ==============
def
_login
(
self
,
email
,
password
):
class
ActivateLoginTest
(
LoginEnrollmentTestCase
):
'''Login. View should always return 200. The success/fail is in the
returned json'''
resp
=
self
.
client
.
post
(
reverse
(
'login'
),
{
'email'
:
email
,
'password'
:
password
})
self
.
assertEqual
(
resp
.
status_code
,
200
)
return
resp
def
login
(
self
,
email
,
password
):
'''Login, check that it worked.'''
resp
=
self
.
_login
(
email
,
password
)
data
=
parse_json
(
resp
)
self
.
assertTrue
(
data
[
'success'
])
return
resp
def
logout
(
self
):
'''Logout, check that it worked.'''
resp
=
self
.
client
.
get
(
reverse
(
'logout'
),
{})
# should redirect
self
.
assertEqual
(
resp
.
status_code
,
302
)
return
resp
def
_create_account
(
self
,
username
,
email
,
password
):
'''Try to create an account. No error checking'''
resp
=
self
.
client
.
post
(
'/create_account'
,
{
'username'
:
username
,
'email'
:
email
,
'password'
:
password
,
'name'
:
'Fred Weasley'
,
'terms_of_service'
:
'true'
,
'honor_code'
:
'true'
,
})
return
resp
def
create_account
(
self
,
username
,
email
,
password
):
'''Create the account and check that it worked'''
resp
=
self
.
_create_account
(
username
,
email
,
password
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
data
=
parse_json
(
resp
)
self
.
assertEqual
(
data
[
'success'
],
True
)
# Check both that the user is created, and inactive
self
.
assertFalse
(
get_user
(
email
)
.
is_active
)
return
resp
def
_activate_user
(
self
,
email
):
'''Look up the activation key for the user, then hit the activate view.
No error checking'''
activation_key
=
get_registration
(
email
)
.
activation_key
# and now we try to activate
url
=
reverse
(
'activate'
,
kwargs
=
{
'key'
:
activation_key
})
resp
=
self
.
client
.
get
(
url
)
return
resp
def
activate_user
(
self
,
email
):
resp
=
self
.
_activate_user
(
email
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# Now make sure that the user is now actually activated
self
.
assertTrue
(
get_user
(
email
)
.
is_active
)
def
try_enroll
(
self
,
course
):
"""Try to enroll. Return bool success instead of asserting it."""
resp
=
self
.
client
.
post
(
'/change_enrollment'
,
{
'enrollment_action'
:
'enroll'
,
'course_id'
:
course
.
id
,
})
print
(
'Enrollment in
%
s result status code:
%
s'
%
(
course
.
location
.
url
(),
str
(
resp
.
status_code
)))
return
resp
.
status_code
==
200
def
enroll
(
self
,
course
):
"""Enroll the currently logged-in user, and check that it worked."""
result
=
self
.
try_enroll
(
course
)
self
.
assertTrue
(
result
)
def
unenroll
(
self
,
course
):
"""Unenroll the currently logged-in user, and check that it worked."""
resp
=
self
.
client
.
post
(
'/change_enrollment'
,
{
'enrollment_action'
:
'unenroll'
,
'course_id'
:
course
.
id
,
})
self
.
assertTrue
(
resp
.
status_code
==
200
)
def
check_for_get_code
(
self
,
code
,
url
):
"""
Check that we got the expected code when accessing url via GET.
Returns the response.
"""
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
code
,
"got code
%
d for url '
%
s'. Expected code
%
d"
%
(
resp
.
status_code
,
url
,
code
))
return
resp
def
check_for_post_code
(
self
,
code
,
url
,
data
=
{}):
"""
"""
Check that we got the expected code when accessing url via POST.
Test logging in and logging out.
Returns the response.
"""
"""
resp
=
self
.
client
.
post
(
url
,
data
)
self
.
assertEqual
(
resp
.
status_code
,
code
,
"got code
%
d for url '
%
s'. Expected code
%
d"
%
(
resp
.
status_code
,
url
,
code
))
return
resp
class
ActivateLoginTest
(
LoginEnrollmentTestCase
):
'''Test logging in and logging out'''
def
setUp
(
self
):
def
setUp
(
self
):
self
.
setup_
viewtest_
user
()
self
.
setup_user
()
def
test_activate_login
(
self
):
def
test_activate_login
(
self
):
'''Test login -- the setup function does all the work'''
"""
Test login -- the setup function does all the work.
"""
pass
pass
def
test_logout
(
self
):
def
test_logout
(
self
):
'''Test logout -- setup function does login'''
"""
Test logout -- setup function does login.
"""
self
.
logout
()
self
.
logout
()
class
PageLoaderTestCase
(
LoginEnrollmentTestCase
):
class
PageLoaderTestCase
(
LoginEnrollmentTestCase
):
''' Base class that adds a function to load all pages in a modulestore '''
"""
Base class that adds a function to load all pages in a modulestore.
"""
def
check_random_page_loads
(
self
,
module_store
):
def
check_random_page_loads
(
self
,
module_store
):
'''
"""
Choose a page in the course randomly, and assert that it loads
Choose a page in the course randomly, and assert that it loads
.
'''
"""
# enroll in the course before trying to access pages
# enroll in the course before trying to access pages
courses
=
module_store
.
get_courses
()
courses
=
module_store
.
get_courses
()
self
.
assertEqual
(
len
(
courses
),
1
)
self
.
assertEqual
(
len
(
courses
),
1
)
course
=
courses
[
0
]
course
=
courses
[
0
]
self
.
enroll
(
course
)
self
.
enroll
(
course
,
True
)
course_id
=
course
.
id
course_id
=
course
.
id
# Search for items in the course
# Search for items in the course
...
@@ -339,12 +99,12 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
...
@@ -339,12 +99,12 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
def
_assert_loads
(
self
,
django_url
,
kwargs
,
descriptor
,
def
_assert_loads
(
self
,
django_url
,
kwargs
,
descriptor
,
expect_redirect
=
False
,
expect_redirect
=
False
,
check_content
=
False
):
check_content
=
False
):
'''
"""
Assert that the url loads correctly.
Assert that the url loads correctly.
If expect_redirect, then also check that we were redirected.
If expect_redirect, then also check that we were redirected.
If check_content, then check that we don't get
If check_content, then check that we don't get
an error message about unavailable modules.
an error message about unavailable modules.
'''
"""
url
=
reverse
(
django_url
,
kwargs
=
kwargs
)
url
=
reverse
(
django_url
,
kwargs
=
kwargs
)
response
=
self
.
client
.
get
(
url
,
follow
=
True
)
response
=
self
.
client
.
get
(
url
,
follow
=
True
)
...
@@ -364,11 +124,13 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
...
@@ -364,11 +124,13 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestCoursesLoadTestCase_XmlModulestore
(
PageLoaderTestCase
):
class
TestCoursesLoadTestCase_XmlModulestore
(
PageLoaderTestCase
):
'''Check that all pages in test courses load properly from XML'''
"""
Check that all pages in test courses load properly from XML.
"""
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestCoursesLoadTestCase_XmlModulestore
,
self
)
.
setUp
()
super
(
TestCoursesLoadTestCase_XmlModulestore
,
self
)
.
setUp
()
self
.
setup_
viewtest_
user
()
self
.
setup_user
()
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
def
test_toy_course_loads
(
self
):
def
test_toy_course_loads
(
self
):
...
@@ -383,11 +145,13 @@ class TestCoursesLoadTestCase_XmlModulestore(PageLoaderTestCase):
...
@@ -383,11 +145,13 @@ class TestCoursesLoadTestCase_XmlModulestore(PageLoaderTestCase):
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestCoursesLoadTestCase_MongoModulestore
(
PageLoaderTestCase
):
class
TestCoursesLoadTestCase_MongoModulestore
(
PageLoaderTestCase
):
'''Check that all pages in test courses load properly from Mongo'''
"""
Check that all pages in test courses load properly from Mongo.
"""
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestCoursesLoadTestCase_MongoModulestore
,
self
)
.
setUp
()
super
(
TestCoursesLoadTestCase_MongoModulestore
,
self
)
.
setUp
()
self
.
setup_
viewtest_
user
()
self
.
setup_user
()
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
modulestore
()
.
collection
.
drop
()
modulestore
()
.
collection
.
drop
()
...
@@ -405,67 +169,6 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase):
...
@@ -405,67 +169,6 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase):
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestNavigation
(
LoginEnrollmentTestCase
):
"""Check that navigation state is saved properly"""
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
# Assume courses are there
self
.
full
=
modulestore
()
.
get_course
(
"edX/full/6.002_Spring_2012"
)
self
.
toy
=
modulestore
()
.
get_course
(
"edX/toy/2012_Fall"
)
# Create two accounts
self
.
student
=
'view@test.com'
self
.
student2
=
'view2@test.com'
self
.
password
=
'foo'
self
.
create_account
(
'u1'
,
self
.
student
,
self
.
password
)
self
.
create_account
(
'u2'
,
self
.
student2
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
self
.
activate_user
(
self
.
student2
)
def
test_accordion_state
(
self
):
"""Make sure that the accordion remembers where you were properly"""
self
.
login
(
self
.
student
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
self
.
enroll
(
self
.
full
)
# First request should redirect to ToyVideos
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
}))
# Don't use no-follow, because state should
# only be saved once we actually hit the section
self
.
assertRedirects
(
resp
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Toy_Videos'
}))
# Hitting the couseware tab again should
# redirect to the first chapter: 'Overview'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
}))
self
.
assertRedirectsNoFollow
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
,
'chapter'
:
'Overview'
}))
# Now we directly navigate to a section in a different chapter
self
.
check_for_get_code
(
200
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
,
'chapter'
:
'secret:magic'
,
'section'
:
'toyvideo'
}))
# And now hitting the courseware tab should redirect to 'secret:magic'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
}))
self
.
assertRedirectsNoFollow
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
,
'chapter'
:
'secret:magic'
}))
@override_settings
(
MODULESTORE
=
TEST_DATA_DRAFT_MONGO_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_DRAFT_MONGO_MODULESTORE
)
class
TestDraftModuleStore
(
TestCase
):
class
TestDraftModuleStore
(
TestCase
):
def
test_get_items_with_course_items
(
self
):
def
test_get_items_with_course_items
(
self
):
...
@@ -478,558 +181,3 @@ class TestDraftModuleStore(TestCase):
...
@@ -478,558 +181,3 @@ class TestDraftModuleStore(TestCase):
# test success is just getting through the above statement.
# test success is just getting through the above statement.
# The bug was that 'course_id' argument was
# The bug was that 'course_id' argument was
# not allowed to be passed in (i.e. was throwing exception)
# not allowed to be passed in (i.e. was throwing exception)
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestViewAuth
(
LoginEnrollmentTestCase
):
"""Check that view authentication works properly"""
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
self
.
full
=
modulestore
()
.
get_course
(
"edX/full/6.002_Spring_2012"
)
self
.
toy
=
modulestore
()
.
get_course
(
"edX/toy/2012_Fall"
)
# Create two accounts
self
.
student
=
'view@test.com'
self
.
instructor
=
'view2@test.com'
self
.
password
=
'foo'
self
.
create_account
(
'u1'
,
self
.
student
,
self
.
password
)
self
.
create_account
(
'u2'
,
self
.
instructor
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
self
.
activate_user
(
self
.
instructor
)
def
test_instructor_pages
(
self
):
"""Make sure only instructors for the course
or staff can load the instructor
dashboard, the grade views, and student profile pages"""
# First, try with an enrolled student
self
.
login
(
self
.
student
,
self
.
password
)
# shouldn't work before enroll
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'about_course'
,
args
=
[
self
.
toy
.
id
]))
self
.
enroll
(
self
.
toy
)
self
.
enroll
(
self
.
full
)
# should work now -- redirect to first page
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
toy
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Toy_Videos'
}))
def
instructor_urls
(
course
):
"list of urls that only instructors/staff should be able to see"
urls
=
[
reverse
(
name
,
kwargs
=
{
'course_id'
:
course
.
id
})
for
name
in
(
'instructor_dashboard'
,
'gradebook'
,
'grade_summary'
,)]
urls
.
append
(
reverse
(
'student_progress'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'student_id'
:
get_user
(
self
.
student
)
.
id
}))
return
urls
# Randomly sample an instructor page
url
=
random
.
choice
(
instructor_urls
(
self
.
toy
)
+
instructor_urls
(
self
.
full
))
# Shouldn't be able to get to the instructor pages
print
'checking for 404 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
404
,
url
)
# Make the instructor staff in the toy course
group_name
=
_course_staff_group_name
(
self
.
toy
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
get_user
(
self
.
instructor
))
self
.
logout
()
self
.
login
(
self
.
instructor
,
self
.
password
)
# Now should be able to get to the toy course, but not the full course
url
=
random
.
choice
(
instructor_urls
(
self
.
toy
))
print
'checking for 200 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
200
,
url
)
url
=
random
.
choice
(
instructor_urls
(
self
.
full
))
print
'checking for 404 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
404
,
url
)
# now also make the instructor staff
instructor
=
get_user
(
self
.
instructor
)
instructor
.
is_staff
=
True
instructor
.
save
()
# and now should be able to load both
url
=
random
.
choice
(
instructor_urls
(
self
.
toy
)
+
instructor_urls
(
self
.
full
))
print
'checking for 200 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
200
,
url
)
def
run_wrapped
(
self
,
test
):
"""
test.py turns off start dates. Enable them.
Because settings is global, be careful not to mess it up for other tests
(Can't use override_settings because we're only changing part of the
MITX_FEATURES dict)
"""
oldDSD
=
settings
.
MITX_FEATURES
[
'DISABLE_START_DATES'
]
try
:
settings
.
MITX_FEATURES
[
'DISABLE_START_DATES'
]
=
False
test
()
finally
:
settings
.
MITX_FEATURES
[
'DISABLE_START_DATES'
]
=
oldDSD
def
test_dark_launch
(
self
):
"""Make sure that before course start, students can't access course
pages, but instructors can"""
self
.
run_wrapped
(
self
.
_do_test_dark_launch
)
def
test_enrollment_period
(
self
):
"""Check that enrollment periods work"""
self
.
run_wrapped
(
self
.
_do_test_enrollment_period
)
def
test_beta_period
(
self
):
"""Check that beta-test access works"""
self
.
run_wrapped
(
self
.
_do_test_beta_period
)
def
_do_test_dark_launch
(
self
):
"""Actually do the test, relying on settings to be right."""
# Make courses start in the future
tomorrow
=
datetime
.
datetime
.
now
(
UTC
())
+
datetime
.
timedelta
(
days
=
1
)
self
.
toy
.
lms
.
start
=
tomorrow
self
.
full
.
lms
.
start
=
tomorrow
self
.
assertFalse
(
self
.
toy
.
has_started
())
self
.
assertFalse
(
self
.
full
.
has_started
())
self
.
assertFalse
(
settings
.
MITX_FEATURES
[
'DISABLE_START_DATES'
])
def
reverse_urls
(
names
,
course
):
"""Reverse a list of course urls"""
return
[
reverse
(
name
,
kwargs
=
{
'course_id'
:
course
.
id
})
for
name
in
names
]
def
dark_student_urls
(
course
):
"""
list of urls that students should be able to see only
after launch, but staff should see before
"""
urls
=
reverse_urls
([
'info'
,
'progress'
],
course
)
urls
.
extend
([
reverse
(
'book'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'book_index'
:
index
})
for
index
,
book
in
enumerate
(
course
.
textbooks
)
])
return
urls
def
light_student_urls
(
course
):
"""
list of urls that students should be able to see before
launch.
"""
urls
=
reverse_urls
([
'about_course'
],
course
)
urls
.
append
(
reverse
(
'courses'
))
return
urls
def
instructor_urls
(
course
):
"""list of urls that only instructors/staff should be able to see"""
urls
=
reverse_urls
([
'instructor_dashboard'
,
'gradebook'
,
'grade_summary'
],
course
)
return
urls
def
check_non_staff
(
course
):
"""Check that access is right for non-staff in course"""
print
'=== Checking non-staff access for {0}'
.
format
(
course
.
id
)
# Randomly sample a dark url
url
=
random
.
choice
(
instructor_urls
(
course
)
+
dark_student_urls
(
course
)
+
reverse_urls
([
'courseware'
],
course
))
print
'checking for 404 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
404
,
url
)
# Randomly sample a light url
url
=
random
.
choice
(
light_student_urls
(
course
))
print
'checking for 200 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
200
,
url
)
def
check_staff
(
course
):
"""Check that access is right for staff in course"""
print
'=== Checking staff access for {0}'
.
format
(
course
.
id
)
# Randomly sample a url
url
=
random
.
choice
(
instructor_urls
(
course
)
+
dark_student_urls
(
course
)
+
light_student_urls
(
course
))
print
'checking for 200 on {0}'
.
format
(
url
)
self
.
check_for_get_code
(
200
,
url
)
# The student progress tab is not accessible to a student
# before launch, so the instructor view-as-student feature
# should return a 404 as well.
# TODO (vshnayder): If this is not the behavior we want, will need
# to make access checking smarter and understand both the effective
# user (the student), and the requesting user (the prof)
url
=
reverse
(
'student_progress'
,
kwargs
=
{
'course_id'
:
course
.
id
,
'student_id'
:
get_user
(
self
.
student
)
.
id
})
print
'checking for 404 on view-as-student: {0}'
.
format
(
url
)
self
.
check_for_get_code
(
404
,
url
)
# The courseware url should redirect, not 200
url
=
reverse_urls
([
'courseware'
],
course
)[
0
]
self
.
check_for_get_code
(
302
,
url
)
# First, try with an enrolled student
print
'=== Testing student access....'
self
.
login
(
self
.
student
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
self
.
enroll
(
self
.
full
)
# shouldn't be able to get to anything except the light pages
check_non_staff
(
self
.
toy
)
check_non_staff
(
self
.
full
)
print
'=== Testing course instructor access....'
# Make the instructor staff in the toy course
group_name
=
_course_staff_group_name
(
self
.
toy
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
get_user
(
self
.
instructor
))
self
.
logout
()
self
.
login
(
self
.
instructor
,
self
.
password
)
# Enroll in the classes---can't see courseware otherwise.
self
.
enroll
(
self
.
toy
)
self
.
enroll
(
self
.
full
)
# should now be able to get to everything for toy course
check_non_staff
(
self
.
full
)
check_staff
(
self
.
toy
)
print
'=== Testing staff access....'
# now also make the instructor staff
instructor
=
get_user
(
self
.
instructor
)
instructor
.
is_staff
=
True
instructor
.
save
()
# and now should be able to load both
check_staff
(
self
.
toy
)
check_staff
(
self
.
full
)
def
_do_test_enrollment_period
(
self
):
"""Actually do the test, relying on settings to be right."""
# Make courses start in the future
tomorrow
=
datetime
.
datetime
.
now
(
UTC
())
+
datetime
.
timedelta
(
days
=
1
)
nextday
=
tomorrow
+
datetime
.
timedelta
(
days
=
1
)
yesterday
=
datetime
.
datetime
.
now
(
UTC
())
-
datetime
.
timedelta
(
days
=
1
)
print
"changing"
# toy course's enrollment period hasn't started
self
.
toy
.
enrollment_start
=
tomorrow
self
.
toy
.
enrollment_end
=
nextday
# full course's has
self
.
full
.
enrollment_start
=
yesterday
self
.
full
.
enrollment_end
=
tomorrow
print
"login"
# First, try with an enrolled student
print
'=== Testing student access....'
self
.
login
(
self
.
student
,
self
.
password
)
self
.
assertFalse
(
self
.
try_enroll
(
self
.
toy
))
self
.
assertTrue
(
self
.
try_enroll
(
self
.
full
))
print
'=== Testing course instructor access....'
# Make the instructor staff in the toy course
group_name
=
_course_staff_group_name
(
self
.
toy
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
get_user
(
self
.
instructor
))
print
"logout/login"
self
.
logout
()
self
.
login
(
self
.
instructor
,
self
.
password
)
print
"Instructor should be able to enroll in toy course"
self
.
assertTrue
(
self
.
try_enroll
(
self
.
toy
))
print
'=== Testing staff access....'
# now make the instructor global staff, but not in the instructor group
group
.
user_set
.
remove
(
get_user
(
self
.
instructor
))
instructor
=
get_user
(
self
.
instructor
)
instructor
.
is_staff
=
True
instructor
.
save
()
# unenroll and try again
self
.
unenroll
(
self
.
toy
)
self
.
assertTrue
(
self
.
try_enroll
(
self
.
toy
))
def
_do_test_beta_period
(
self
):
"""Actually test beta periods, relying on settings to be right."""
# trust, but verify :)
self
.
assertFalse
(
settings
.
MITX_FEATURES
[
'DISABLE_START_DATES'
])
# Make courses start in the future
tomorrow
=
datetime
.
datetime
.
now
(
UTC
())
+
datetime
.
timedelta
(
days
=
1
)
# toy course's hasn't started
self
.
toy
.
lms
.
start
=
tomorrow
self
.
assertFalse
(
self
.
toy
.
has_started
())
# but should be accessible for beta testers
self
.
toy
.
lms
.
days_early_for_beta
=
2
# student user shouldn't see it
student_user
=
get_user
(
self
.
student
)
self
.
assertFalse
(
has_access
(
student_user
,
self
.
toy
,
'load'
))
# now add the student to the beta test group
group_name
=
course_beta_test_group_name
(
self
.
toy
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
student_user
)
# now the student should see it
self
.
assertTrue
(
has_access
(
student_user
,
self
.
toy
,
'load'
))
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestSubmittingProblems
(
LoginEnrollmentTestCase
):
"""Check that a course gets graded properly"""
# Subclasses should specify the course slug
course_slug
=
"UNKNOWN"
course_when
=
"UNKNOWN"
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
course_name
=
"edX/
%
s/
%
s"
%
(
self
.
course_slug
,
self
.
course_when
)
self
.
course
=
modulestore
()
.
get_course
(
course_name
)
assert
self
.
course
,
"Couldn't load course
%
r"
%
course_name
# create a test student
self
.
student
=
'view@test.com'
self
.
password
=
'foo'
self
.
create_account
(
'u1'
,
self
.
student
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
self
.
enroll
(
self
.
course
)
self
.
student_user
=
get_user
(
self
.
student
)
self
.
factory
=
RequestFactory
()
def
problem_location
(
self
,
problem_url_name
):
return
"i4x://edX/{}/problem/{}"
.
format
(
self
.
course_slug
,
problem_url_name
)
def
modx_url
(
self
,
problem_location
,
dispatch
):
return
reverse
(
'modx_dispatch'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'location'
:
problem_location
,
'dispatch'
:
dispatch
,
}
)
def
submit_question_answer
(
self
,
problem_url_name
,
responses
):
"""
Submit answers to a question.
Responses is a dict mapping problem ids (not sure of the right term)
to answers:
{'2_1': 'Correct', '2_2': 'Incorrect'}
"""
problem_location
=
self
.
problem_location
(
problem_url_name
)
modx_url
=
self
.
modx_url
(
problem_location
,
'problem_check'
)
answer_key_prefix
=
'input_i4x-edX-{}-problem-{}_'
.
format
(
self
.
course_slug
,
problem_url_name
)
resp
=
self
.
client
.
post
(
modx_url
,
{
(
answer_key_prefix
+
k
):
v
for
k
,
v
in
responses
.
items
()
}
)
return
resp
def
reset_question_answer
(
self
,
problem_url_name
):
'''resets specified problem for current user'''
problem_location
=
self
.
problem_location
(
problem_url_name
)
modx_url
=
self
.
modx_url
(
problem_location
,
'problem_reset'
)
resp
=
self
.
client
.
post
(
modx_url
)
return
resp
class
TestCourseGrader
(
TestSubmittingProblems
):
"""Check that a course gets graded properly"""
course_slug
=
"graded"
course_when
=
"2012_Fall"
def
get_grade_summary
(
self
):
'''calls grades.grade for current user and course'''
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
self
.
course
.
id
,
self
.
student_user
,
self
.
course
)
fake_request
=
self
.
factory
.
get
(
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
return
grades
.
grade
(
self
.
student_user
,
fake_request
,
self
.
course
,
model_data_cache
)
def
get_homework_scores
(
self
):
'''get scores for homeworks'''
return
self
.
get_grade_summary
()[
'totaled_scores'
][
'Homework'
]
def
get_progress_summary
(
self
):
'''return progress summary structure for current user and course'''
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
self
.
course
.
id
,
self
.
student_user
,
self
.
course
)
fake_request
=
self
.
factory
.
get
(
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
progress_summary
=
grades
.
progress_summary
(
self
.
student_user
,
fake_request
,
self
.
course
,
model_data_cache
)
return
progress_summary
def
check_grade_percent
(
self
,
percent
):
'''assert that percent grade is as expected'''
grade_summary
=
self
.
get_grade_summary
()
self
.
assertEqual
(
grade_summary
[
'percent'
],
percent
)
def
test_get_graded
(
self
):
#### Check that the grader shows we have 0% in the course
self
.
check_grade_percent
(
0
)
#### Submit the answers to a few problems as ajax calls
def
earned_hw_scores
():
"""Global scores, each Score is a Problem Set"""
return
[
s
.
earned
for
s
in
self
.
get_homework_scores
()]
def
score_for_hw
(
hw_url_name
):
"""returns list of scores for a given url"""
hw_section
=
[
section
for
section
in
self
.
get_progress_summary
()[
0
][
'sections'
]
if
section
.
get
(
'url_name'
)
==
hw_url_name
][
0
]
return
[
s
.
earned
for
s
in
hw_section
[
'scores'
]]
# Only get half of the first problem correct
self
.
submit_question_answer
(
'H1P1'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Incorrect'
})
self
.
check_grade_percent
(
0.06
)
self
.
assertEqual
(
earned_hw_scores
(),
[
1.0
,
0
,
0
])
# Order matters
self
.
assertEqual
(
score_for_hw
(
'Homework1'
),
[
1.0
,
0.0
])
# Get both parts of the first problem correct
self
.
reset_question_answer
(
'H1P1'
)
self
.
submit_question_answer
(
'H1P1'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.13
)
self
.
assertEqual
(
earned_hw_scores
(),
[
2.0
,
0
,
0
])
self
.
assertEqual
(
score_for_hw
(
'Homework1'
),
[
2.0
,
0.0
])
# This problem is shown in an ABTest
self
.
submit_question_answer
(
'H1P2'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.25
)
self
.
assertEqual
(
earned_hw_scores
(),
[
4.0
,
0.0
,
0
])
self
.
assertEqual
(
score_for_hw
(
'Homework1'
),
[
2.0
,
2.0
])
# This problem is hidden in an ABTest.
# Getting it correct doesn't change total grade
self
.
submit_question_answer
(
'H1P3'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.25
)
self
.
assertEqual
(
score_for_hw
(
'Homework1'
),
[
2.0
,
2.0
])
# On the second homework, we only answer half of the questions.
# Then it will be dropped when homework three becomes the higher percent
# This problem is also weighted to be 4 points (instead of default of 2)
# If the problem was unweighted the percent would have been 0.38 so we
# know it works.
self
.
submit_question_answer
(
'H2P1'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.42
)
self
.
assertEqual
(
earned_hw_scores
(),
[
4.0
,
4.0
,
0
])
# Third homework
self
.
submit_question_answer
(
'H3P1'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.42
)
# Score didn't change
self
.
assertEqual
(
earned_hw_scores
(),
[
4.0
,
4.0
,
2.0
])
self
.
submit_question_answer
(
'H3P2'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
0.5
)
# Now homework2 dropped. Score changes
self
.
assertEqual
(
earned_hw_scores
(),
[
4.0
,
4.0
,
4.0
])
# Now we answer the final question (worth half of the grade)
self
.
submit_question_answer
(
'FinalQuestion'
,
{
'2_1'
:
'Correct'
,
'2_2'
:
'Correct'
})
self
.
check_grade_percent
(
1.0
)
# Hooray! We got 100%
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestSchematicResponse
(
TestSubmittingProblems
):
"""Check that we can submit a schematic response, and it answers properly."""
course_slug
=
"embedded_python"
course_when
=
"2013_Spring"
def
test_schematic
(
self
):
resp
=
self
.
submit_question_answer
(
'schematic_problem'
,
{
'2_1'
:
json
.
dumps
(
[[
'transient'
,
{
'Z'
:
[
[
0.0000004
,
2.8
],
[
0.0000009
,
2.8
],
[
0.0000014
,
2.8
],
[
0.0000019
,
2.8
],
[
0.0000024
,
2.8
],
[
0.0000029
,
0.2
],
[
0.0000034
,
0.2
],
[
0.0000039
,
0.2
]
]}]]
)
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'correct'
)
self
.
reset_question_answer
(
'schematic_problem'
)
resp
=
self
.
submit_question_answer
(
'schematic_problem'
,
{
'2_1'
:
json
.
dumps
(
[[
'transient'
,
{
'Z'
:
[
[
0.0000004
,
2.8
],
[
0.0000009
,
0.0
],
# wrong.
[
0.0000014
,
2.8
],
[
0.0000019
,
2.8
],
[
0.0000024
,
2.8
],
[
0.0000029
,
0.2
],
[
0.0000034
,
0.2
],
[
0.0000039
,
0.2
]
]}]]
)
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'incorrect'
)
def
test_check_function
(
self
):
resp
=
self
.
submit_question_answer
(
'cfn_problem'
,
{
'2_1'
:
"0, 1, 2, 3, 4, 5, 'Outside of loop', 6"
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'correct'
)
self
.
reset_question_answer
(
'cfn_problem'
)
resp
=
self
.
submit_question_answer
(
'cfn_problem'
,
{
'2_1'
:
"xyzzy!"
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'incorrect'
)
def
test_computed_answer
(
self
):
resp
=
self
.
submit_question_answer
(
'computed_answer'
,
{
'2_1'
:
"Xyzzy"
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'correct'
)
self
.
reset_question_answer
(
'computed_answer'
)
resp
=
self
.
submit_question_answer
(
'computed_answer'
,
{
'2_1'
:
"NO!"
})
respdata
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
respdata
[
'success'
],
'incorrect'
)
lms/djangoapps/instructor/tests/test_download_csv.py
View file @
7d0b72a4
...
@@ -11,12 +11,13 @@ django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/inst
...
@@ -11,12 +11,13 @@ django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/inst
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
# Need access to internal func to put users in the right group
# Need access to internal func to put users in the right group
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
,
User
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
courseware.access
import
_course_staff_group_name
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_XML_MODULESTORE
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
import
xmodule.modulestore.django
import
xmodule.modulestore.django
...
@@ -45,7 +46,7 @@ class TestInstructorDashboardGradeDownloadCSV(LoginEnrollmentTestCase):
...
@@ -45,7 +46,7 @@ class TestInstructorDashboardGradeDownloadCSV(LoginEnrollmentTestCase):
def
make_instructor
(
course
):
def
make_instructor
(
course
):
group_name
=
_course_staff_group_name
(
course
.
location
)
group_name
=
_course_staff_group_name
(
course
.
location
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
.
user_set
.
add
(
get_user
(
self
.
instructor
))
g
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
self
.
instructor
))
make_instructor
(
self
.
toy
)
make_instructor
(
self
.
toy
)
...
@@ -72,7 +73,7 @@ class TestInstructorDashboardGradeDownloadCSV(LoginEnrollmentTestCase):
...
@@ -72,7 +73,7 @@ class TestInstructorDashboardGradeDownloadCSV(LoginEnrollmentTestCase):
# All the not-actually-in-the-course hw and labs come from the
# All the not-actually-in-the-course hw and labs come from the
# default grading policy string in graders.py
# default grading policy string in graders.py
expected_body
=
'''"ID","Username","Full Name","edX email","External email","HW 01","HW 02","HW 03","HW 04","HW 05","HW 06","HW 07","HW 08","HW 09","HW 10","HW 11","HW 12","HW Avg","Lab 01","Lab 02","Lab 03","Lab 04","Lab 05","Lab 06","Lab 07","Lab 08","Lab 09","Lab 10","Lab 11","Lab 12","Lab Avg","Midterm","Final"
expected_body
=
'''"ID","Username","Full Name","edX email","External email","HW 01","HW 02","HW 03","HW 04","HW 05","HW 06","HW 07","HW 08","HW 09","HW 10","HW 11","HW 12","HW Avg","Lab 01","Lab 02","Lab 03","Lab 04","Lab 05","Lab 06","Lab 07","Lab 08","Lab 09","Lab 10","Lab 11","Lab 12","Lab Avg","Midterm","Final"
"2","u2","
Fred Weasley
","view2@test.com","","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"
"2","u2","
username
","view2@test.com","","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"
'''
'''
self
.
assertEqual
(
body
,
expected_body
,
msg
)
self
.
assertEqual
(
body
,
expected_body
,
msg
)
lms/djangoapps/instructor/tests/test_enrollment.py
View file @
7d0b72a4
...
@@ -7,7 +7,8 @@ from django.test.utils import override_settings
...
@@ -7,7 +7,8 @@ from django.test.utils import override_settings
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
courseware.access
import
_course_staff_group_name
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_XML_MODULESTORE
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
student.tests.factories
import
UserFactory
,
CourseEnrollmentFactory
,
AdminFactory
from
student.tests.factories
import
UserFactory
,
CourseEnrollmentFactory
,
AdminFactory
...
...
lms/djangoapps/instructor/tests/test_forum_admin.py
View file @
7d0b72a4
...
@@ -6,7 +6,7 @@ Unit tests for instructor dashboard forum administration
...
@@ -6,7 +6,7 @@ Unit tests for instructor dashboard forum administration
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
# Need access to internal func to put users in the right group
# Need access to internal func to put users in the right group
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
,
User
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django_comment_common.models
import
Role
,
FORUM_ROLE_ADMINISTRATOR
,
\
from
django_comment_common.models
import
Role
,
FORUM_ROLE_ADMINISTRATOR
,
\
...
@@ -14,7 +14,8 @@ from django_comment_common.models import Role, FORUM_ROLE_ADMINISTRATOR, \
...
@@ -14,7 +14,8 @@ from django_comment_common.models import Role, FORUM_ROLE_ADMINISTRATOR, \
from
django_comment_client.utils
import
has_forum_access
from
django_comment_client.utils
import
has_forum_access
from
courseware.access
import
_course_staff_group_name
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_XML_MODULESTORE
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
import
xmodule.modulestore.django
import
xmodule.modulestore.django
...
@@ -55,7 +56,7 @@ class TestInstructorDashboardForumAdmin(LoginEnrollmentTestCase):
...
@@ -55,7 +56,7 @@ class TestInstructorDashboardForumAdmin(LoginEnrollmentTestCase):
group_name
=
_course_staff_group_name
(
self
.
toy
.
location
)
group_name
=
_course_staff_group_name
(
self
.
toy
.
location
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
.
user_set
.
add
(
get_user
(
self
.
instructor
))
g
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
self
.
instructor
))
self
.
logout
()
self
.
logout
()
self
.
login
(
self
.
instructor
,
self
.
password
)
self
.
login
(
self
.
instructor
,
self
.
password
)
...
...
lms/djangoapps/open_ended_grading/tests.py
View file @
7d0b72a4
...
@@ -8,7 +8,7 @@ import json
...
@@ -8,7 +8,7 @@ import json
from
mock
import
MagicMock
,
patch
,
Mock
from
mock
import
MagicMock
,
patch
,
Mock
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
,
User
from
django.conf
import
settings
from
django.conf
import
settings
from
mitxmako.shortcuts
import
render_to_string
from
mitxmako.shortcuts
import
render_to_string
...
@@ -20,7 +20,6 @@ from xmodule.x_module import ModuleSystem
...
@@ -20,7 +20,6 @@ from xmodule.x_module import ModuleSystem
from
open_ended_grading
import
staff_grading_service
,
views
from
open_ended_grading
import
staff_grading_service
,
views
from
courseware.access
import
_course_staff_group_name
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
import
logging
import
logging
...
@@ -30,6 +29,9 @@ from django.test.utils import override_settings
...
@@ -30,6 +29,9 @@ from django.test.utils import override_settings
from
xmodule.tests
import
test_util_open_ended
from
xmodule.tests
import
test_util_open_ended
from
courseware.tests
import
factories
from
courseware.tests
import
factories
from
courseware.tests.modulestore_config
import
TEST_DATA_XML_MODULESTORE
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
,
check_for_get_code
,
check_for_post_code
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestStaffGradingService
(
LoginEnrollmentTestCase
):
class
TestStaffGradingService
(
LoginEnrollmentTestCase
):
...
@@ -57,7 +59,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
...
@@ -57,7 +59,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
def
make_instructor
(
course
):
def
make_instructor
(
course
):
group_name
=
_course_staff_group_name
(
course
.
location
)
group_name
=
_course_staff_group_name
(
course
.
location
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
=
Group
.
objects
.
create
(
name
=
group_name
)
group
.
user_set
.
add
(
get_user
(
self
.
instructor
))
group
.
user_set
.
add
(
User
.
objects
.
get
(
email
=
self
.
instructor
))
make_instructor
(
self
.
toy
)
make_instructor
(
self
.
toy
)
...
@@ -74,8 +76,8 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
...
@@ -74,8 +76,8 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
# both get and post should return 404
# both get and post should return 404
for
view_name
in
(
'staff_grading_get_next'
,
'staff_grading_save_grade'
):
for
view_name
in
(
'staff_grading_get_next'
,
'staff_grading_save_grade'
):
url
=
reverse
(
view_name
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
url
=
reverse
(
view_name
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
self
.
check_for_get_code
(
404
,
url
)
check_for_get_code
(
self
,
404
,
url
)
self
.
check_for_post_code
(
404
,
url
)
check_for_post_code
(
self
,
404
,
url
)
def
test_get_next
(
self
):
def
test_get_next
(
self
):
self
.
login
(
self
.
instructor
,
self
.
password
)
self
.
login
(
self
.
instructor
,
self
.
password
)
...
@@ -83,7 +85,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
...
@@ -83,7 +85,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
url
=
reverse
(
'staff_grading_get_next'
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
url
=
reverse
(
'staff_grading_get_next'
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
data
=
{
'location'
:
self
.
location
}
data
=
{
'location'
:
self
.
location
}
response
=
self
.
check_for_post_code
(
200
,
url
,
data
)
response
=
check_for_post_code
(
self
,
200
,
url
,
data
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
...
@@ -112,7 +114,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
...
@@ -112,7 +114,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
if
skip
:
if
skip
:
data
.
update
({
'skipped'
:
True
})
data
.
update
({
'skipped'
:
True
})
response
=
self
.
check_for_post_code
(
200
,
url
,
data
)
response
=
check_for_post_code
(
self
,
200
,
url
,
data
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
assertTrue
(
content
[
'success'
],
str
(
content
))
self
.
assertTrue
(
content
[
'success'
],
str
(
content
))
self
.
assertEquals
(
content
[
'submission_id'
],
self
.
mock_service
.
cnt
)
self
.
assertEquals
(
content
[
'submission_id'
],
self
.
mock_service
.
cnt
)
...
@@ -129,7 +131,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
...
@@ -129,7 +131,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase):
url
=
reverse
(
'staff_grading_get_problem_list'
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
url
=
reverse
(
'staff_grading_get_problem_list'
,
kwargs
=
{
'course_id'
:
self
.
course_id
})
data
=
{}
data
=
{}
response
=
self
.
check_for_post_code
(
200
,
url
,
data
)
response
=
check_for_post_code
(
self
,
200
,
url
,
data
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
assertTrue
(
content
[
'success'
],
str
(
content
))
self
.
assertTrue
(
content
[
'success'
],
str
(
content
))
...
...
lms/urls.py
View file @
7d0b72a4
...
@@ -37,7 +37,7 @@ urlpatterns = ('', # nopep8
...
@@ -37,7 +37,7 @@ urlpatterns = ('', # nopep8
url
(
r'^login_ajax$'
,
'student.views.login_user'
,
name
=
"login"
),
url
(
r'^login_ajax$'
,
'student.views.login_user'
,
name
=
"login"
),
url
(
r'^login_ajax/(?P<error>[^/]*)$'
,
'student.views.login_user'
),
url
(
r'^login_ajax/(?P<error>[^/]*)$'
,
'student.views.login_user'
),
url
(
r'^logout$'
,
'student.views.logout_user'
,
name
=
'logout'
),
url
(
r'^logout$'
,
'student.views.logout_user'
,
name
=
'logout'
),
url
(
r'^create_account$'
,
'student.views.create_account'
),
url
(
r'^create_account$'
,
'student.views.create_account'
,
name
=
'create_account'
),
url
(
r'^activate/(?P<key>[^/]*)$'
,
'student.views.activate_account'
,
name
=
"activate"
),
url
(
r'^activate/(?P<key>[^/]*)$'
,
'student.views.activate_account'
,
name
=
"activate"
),
url
(
r'^begin_exam_registration/(?P<course_id>[^/]+/[^/]+/[^/]+)$'
,
'student.views.begin_exam_registration'
,
name
=
"begin_exam_registration"
),
url
(
r'^begin_exam_registration/(?P<course_id>[^/]+/[^/]+/[^/]+)$'
,
'student.views.begin_exam_registration'
,
name
=
"begin_exam_registration"
),
...
...
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