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
07486a4d
Commit
07486a4d
authored
Jun 17, 2013
by
Jean Manuel Nater
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactoring the code in tests.py to remove unnecessary dependencies on the XML Modulestore.
parent
a25a0d71
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1057 additions
and
531 deletions
+1057
-531
common/djangoapps/student/views.py
+1
-1
common/lib/xmodule/xmodule/modulestore/tests/factories.py
+6
-1
lms/djangoapps/courseware/tests/mongo_login_helpers.py
+191
-0
lms/djangoapps/courseware/tests/test_navigation.py
+440
-0
lms/djangoapps/courseware/tests/test_view_authentication.py
+418
-0
lms/djangoapps/courseware/tests/tests.py
+1
-529
No files found.
common/djangoapps/student/views.py
View file @
07486a4d
...
...
@@ -349,6 +349,7 @@ def change_enrollment(request):
return
HttpResponseBadRequest
(
"Course id not specified"
)
if
action
==
"enroll"
:
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
try
:
...
...
@@ -357,7 +358,6 @@ def change_enrollment(request):
log
.
warning
(
"User {0} tried to enroll in non-existent course {1}"
.
format
(
user
.
username
,
course_id
))
return
HttpResponseBadRequest
(
"Course id is invalid"
)
if
not
has_access
(
user
,
course
,
'enroll'
):
return
HttpResponseBadRequest
(
"Enrollment is closed"
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/factories.py
View file @
07486a4d
from
factory
import
Factory
,
lazy_attribute_sequence
,
lazy_attribute
from
time
import
gmtime
from
time
import
gmtime
,
time
from
uuid
import
uuid4
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.django
import
modulestore
...
...
@@ -35,7 +35,10 @@ class XModuleCourseFactory(Factory):
if
display_name
is
not
None
:
new_course
.
display_name
=
display_name
tomorrow
=
time
()
+
24
*
3600
new_course
.
lms
.
start
=
gmtime
()
new_course
.
enrollment_start
=
gmtime
(
tomorrow
)
new_course
.
tabs
=
kwargs
.
get
(
'tabs'
,
[
...
...
@@ -55,6 +58,8 @@ class XModuleCourseFactory(Factory):
if
data
is
not
None
:
store
.
update_item
(
new_course
.
location
,
data
)
new_course
=
store
.
get_instance
(
new_course
.
id
,
new_course
.
location
)
return
new_course
...
...
lms/djangoapps/courseware/tests/mongo_login_helpers.py
0 → 100644
View file @
07486a4d
import
logging
import
json
from
urlparse
import
urlsplit
,
urlunsplit
from
django.contrib.auth.models
import
User
,
Group
from
django.test
import
TestCase
from
django.test.client
import
RequestFactory
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
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.modulestore.django
import
modulestore
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
xmodule.modulestore.xml
import
XMLModuleStore
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.mongo
import
MongoModuleStore
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
)
class
MongoLoginHelpers
(
ModuleStoreTestCase
):
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
):
'''create a user account, activate, and log in'''
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
):
'''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.
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
lms/djangoapps/courseware/tests/test_navigation.py
0 → 100644
View file @
07486a4d
import
logging
import
json
import
random
from
urlparse
import
urlsplit
,
urlunsplit
from
uuid
import
uuid4
from
django.contrib.auth.models
import
User
from
django.test
import
TestCase
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
import
xmodule.modulestore.django
from
student.models
import
Registration
from
xmodule.error_module
import
ErrorDescriptor
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
xmodule.modulestore.xml
import
XMLModuleStore
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
mongo_login_helpers
import
*
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
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
):
'''create a user account, activate, and log in'''
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
):
'''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.
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
):
self
.
setup_viewtest_user
()
def
test_activate_login
(
self
):
'''Test login -- the setup function does all the work'''
pass
def
test_logout
(
self
):
'''Test logout -- setup function does login'''
self
.
logout
()
class
PageLoaderTestCase
(
LoginEnrollmentTestCase
):
''' Base class that adds a function to load all pages in a modulestore '''
def
check_random_page_loads
(
self
,
module_store
):
'''
Choose a page in the course randomly, and assert that it loads
'''
# enroll in the course before trying to access pages
courses
=
module_store
.
get_courses
()
self
.
assertEqual
(
len
(
courses
),
1
)
course
=
courses
[
0
]
self
.
enroll
(
course
)
course_id
=
course
.
id
# Search for items in the course
# None is treated as a wildcard
course_loc
=
course
.
location
location_query
=
Location
(
course_loc
.
tag
,
course_loc
.
org
,
course_loc
.
course
,
None
,
None
,
None
)
items
=
module_store
.
get_items
(
location_query
)
if
len
(
items
)
<
1
:
self
.
fail
(
'Could not retrieve any items from course'
)
else
:
descriptor
=
random
.
choice
(
items
)
# We have ancillary course information now as modules
# and we can't simply use 'jump_to' to view them
if
descriptor
.
location
.
category
==
'about'
:
self
.
_assert_loads
(
'about_course'
,
{
'course_id'
:
course_id
},
descriptor
)
elif
descriptor
.
location
.
category
==
'static_tab'
:
kwargs
=
{
'course_id'
:
course_id
,
'tab_slug'
:
descriptor
.
location
.
name
}
self
.
_assert_loads
(
'static_tab'
,
kwargs
,
descriptor
)
elif
descriptor
.
location
.
category
==
'course_info'
:
self
.
_assert_loads
(
'info'
,
{
'course_id'
:
course_id
},
descriptor
)
elif
descriptor
.
location
.
category
==
'custom_tag_template'
:
pass
else
:
kwargs
=
{
'course_id'
:
course_id
,
'location'
:
descriptor
.
location
.
url
()}
self
.
_assert_loads
(
'jump_to'
,
kwargs
,
descriptor
,
expect_redirect
=
True
,
check_content
=
True
)
def
_assert_loads
(
self
,
django_url
,
kwargs
,
descriptor
,
expect_redirect
=
False
,
check_content
=
False
):
'''
Assert that the url loads correctly.
If expect_redirect, then also check that we were redirected.
If check_content, then check that we don't get
an error message about unavailable modules.
'''
url
=
reverse
(
django_url
,
kwargs
=
kwargs
)
response
=
self
.
client
.
get
(
url
,
follow
=
True
)
if
response
.
status_code
!=
200
:
self
.
fail
(
'Status
%
d for page
%
s'
%
(
response
.
status_code
,
descriptor
.
location
.
url
()))
if
expect_redirect
:
self
.
assertEqual
(
response
.
redirect_chain
[
0
][
1
],
302
)
if
check_content
:
unavailable_msg
=
"this module is temporarily unavailable"
self
.
assertEqual
(
response
.
content
.
find
(
unavailable_msg
),
-
1
)
self
.
assertFalse
(
isinstance
(
descriptor
,
ErrorDescriptor
))
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestCoursesLoadTestCase_XmlModulestore
(
PageLoaderTestCase
):
'''Check that all pages in test courses load properly from XML'''
def
setUp
(
self
):
super
(
TestCoursesLoadTestCase_XmlModulestore
,
self
)
.
setUp
()
self
.
setup_viewtest_user
()
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
def
test_toy_course_loads
(
self
):
module_class
=
'xmodule.hidden_module.HiddenDescriptor'
module_store
=
XMLModuleStore
(
TEST_DATA_DIR
,
default_class
=
module_class
,
course_dirs
=
[
'toy'
],
load_error_modules
=
True
)
self
.
check_random_page_loads
(
module_store
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestCoursesLoadTestCase_MongoModulestore
(
PageLoaderTestCase
):
'''Check that all pages in test courses load properly from Mongo'''
def
setUp
(
self
):
super
(
TestCoursesLoadTestCase_MongoModulestore
,
self
)
.
setUp
()
self
.
setup_viewtest_user
()
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
modulestore
()
.
collection
.
drop
()
def
test_toy_course_loads
(
self
):
module_store
=
modulestore
()
import_from_xml
(
module_store
,
TEST_DATA_DIR
,
[
'toy'
])
self
.
check_random_page_loads
(
module_store
)
def
test_full_textbooks_loads
(
self
):
module_store
=
modulestore
()
import_from_xml
(
module_store
,
TEST_DATA_DIR
,
[
'full'
])
course
=
module_store
.
get_item
(
Location
([
'i4x'
,
'edX'
,
'full'
,
'course'
,
'6.002_Spring_2012'
,
None
]))
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestNavigation
(
MongoLoginHelpers
):
"""Check that navigation state is saved properly"""
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
self
.
course
=
CourseFactory
.
create
()
self
.
full
=
CourseFactory
.
create
(
display_name
=
'Robot_Sub_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 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
.
course
)
self
.
enroll
(
self
.
full
)
# First request should redirect to ToyVideos
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
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
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
# Hitting the couseware tab again should
# redirect to the first chapter: 'Overview'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
course
.
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
.
course
.
id
,
'chapter'
:
'factory_chapter'
,
'section'
:
'factory_section'
}))
# And now hitting the courseware tab should redirect to 'secret:magic'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
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 @
07486a4d
import
logging
import
time
import
datetime
import
pytz
import
random
from
uuid
import
uuid4
from
django.contrib.auth.models
import
User
,
Group
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
import
xmodule.modulestore.django
# 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
)
from
mongo_login_helpers
import
MongoLoginHelpers
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
log
=
logging
.
getLogger
(
"mitx."
+
__name__
)
def
get_user
(
email
):
'''look up a user by email'''
return
User
.
objects
.
get
(
email
=
email
)
def
update_course
(
course
,
data
):
"""
Updates the version of course in the mongo modulestore
with the metadata in data and returns the updated version.
"""
store
=
xmodule
.
modulestore
.
django
.
modulestore
()
store
.
update_item
(
course
.
location
,
data
)
store
.
update_metadata
(
course
.
location
,
data
)
updated_course
=
store
.
get_instance
(
course
.
id
,
course
.
location
)
return
updated_course
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
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
TEST_DATA_MONGO_MODULESTORE
=
mongo_store_config
(
TEST_DATA_DIR
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestViewAuth
(
MongoLoginHelpers
):
"""Check that view authentication works properly"""
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
self
.
full
=
CourseFactory
.
create
(
display_name
=
'Robot_Sub_Course'
)
self
.
course
=
CourseFactory
.
create
()
self
.
overview_chapter
=
ItemFactory
.
create
(
display_name
=
'Overview'
)
self
.
progress_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'progress'
)
self
.
info_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'info'
)
self
.
welcome_section
=
ItemFactory
.
create
(
parent_location
=
self
.
overview_chapter
.
location
,
display_name
=
'Welcome'
)
self
.
somewhere_in_progress
=
ItemFactory
.
create
(
parent_location
=
self
.
progress_chapter
.
location
,
display_name
=
'1'
)
# 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
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
]))
self
.
enroll
(
self
.
course
)
self
.
enroll
(
self
.
full
)
# should work now -- redirect to first page
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
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
.
course
)
+
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
.
course
.
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
.
course
))
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
.
course
)
+
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
=
time
.
time
()
+
24
*
3600
self
.
course
.
start
=
time
.
gmtime
(
tomorrow
)
self
.
full
.
start
=
time
.
gmtime
(
tomorrow
)
self
.
assertFalse
(
self
.
course
.
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
.
course
)
self
.
enroll
(
self
.
full
)
# shouldn't be able to get to anything except the light pages
check_non_staff
(
self
.
course
)
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
.
course
.
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
.
course
)
self
.
enroll
(
self
.
full
)
# should now be able to get to everything for self.course
check_non_staff
(
self
.
full
)
check_staff
(
self
.
course
)
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
.
course
)
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
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
}
full_data
=
{
'enrollment_start'
:
yesterday
,
'enrollment_end'
:
tomorrow
}
print
"changing"
# self.course's enrollment period hasn't started
print
self
.
course
.
enrollment_start
self
.
course
=
update_course
(
self
.
course
,
course_data
)
print
'FLAG'
print
self
.
course
.
enrollment_start
print
'FLAG'
#self.course.enrollment_start = time.gmtime(tomorrow)
#self.course.enrollment_end = time.gmtime(nextday)
# full course's has
print
self
.
full
.
enrollment_start
self
.
full
=
update_course
(
self
.
full
,
full_data
)
print
self
.
full
.
enrollment_start
#self.full.enrollment_start = time.gmtime(yesterday)
#self.full.enrollment_end = time.gmtime(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
.
course
))
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
.
course
.
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
.
course
))
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
.
course
)
self
.
assertTrue
(
self
.
try_enroll
(
self
.
course
))
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
=
time
.
time
()
+
24
*
3600
# nextday = tomorrow + 24 * 3600
# yesterday = time.time() - 24 * 3600
# toy course's hasn't started
self
.
course
.
lms
.
start
=
time
.
gmtime
(
tomorrow
)
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
=
get_user
(
self
.
student
)
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 @
07486a4d
...
...
@@ -121,118 +121,6 @@ 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
MongoLoginHelpers
(
ModuleStoreTestCase
):
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
_login
(
self
,
email
,
password
):
'''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
enroll
(
self
,
course
):
"""Enroll the currently logged-in user, and check that it worked."""
result
=
self
.
try_enroll
(
course
)
self
.
assertTrue
(
result
)
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
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
class
LoginEnrollmentTestCase
(
TestCase
):
...
...
@@ -520,84 +408,6 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase):
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
#@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
class
TestNavigation
(
MongoLoginHelpers
):
#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")
self
.
course
=
CourseFactory
.
create
()
self
.
full
=
CourseFactory
.
create
(
display_name
=
'RoboboboboBOT'
)
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 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
.
course
)
self
.
enroll
(
self
.
full
)
# First request should redirect to ToyVideos
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
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
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
# Hitting the couseware tab again should
# redirect to the first chapter: 'Overview'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
course
.
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
.
course
.
id
,
'chapter'
:
'factory_chapter'
,
'section'
:
'factory_section'
}))
# And now hitting the courseware tab should redirect to 'secret:magic'
resp
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
resp
,
reverse
(
'courseware_chapter'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'factory_chapter'
}))
@override_settings
(
MODULESTORE
=
TEST_DATA_DRAFT_MONGO_MODULESTORE
)
class
TestDraftModuleStore
(
TestCase
):
...
...
@@ -612,345 +422,6 @@ class TestDraftModuleStore(TestCase):
# The bug was that 'course_id' argument was
# not allowed to be passed in (i.e. was throwing exception)
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestViewAuth
(
MongoLoginHelpers
):
"""Check that view authentication works properly"""
def
setUp
(
self
):
xmodule
.
modulestore
.
django
.
_MODULESTORES
=
{}
self
.
full
=
CourseFactory
.
create
(
display_name
=
'Robot_Sub_Course'
)
self
.
course
=
CourseFactory
.
create
()
self
.
overview_chapter
=
ItemFactory
.
create
(
display_name
=
'Overview'
)
self
.
progress_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'progress'
)
self
.
info_chapter
=
ItemFactory
.
create
(
parent_location
=
self
.
course
.
location
,
display_name
=
'info'
)
self
.
welcome_section
=
ItemFactory
.
create
(
parent_location
=
self
.
overview_chapter
.
location
,
display_name
=
'Welcome'
)
self
.
somewhere_in_progress
=
ItemFactory
.
create
(
parent_location
=
self
.
progress_chapter
.
location
,
display_name
=
'1'
)
# 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
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
]))
self
.
enroll
(
self
.
course
)
self
.
enroll
(
self
.
full
)
# should work now -- redirect to first page
response
=
self
.
client
.
get
(
reverse
(
'courseware'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
}))
self
.
assertRedirectsNoFollow
(
response
,
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
,
'chapter'
:
'Overview'
,
'section'
:
'Welcome'
}))
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
.
course
)
+
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
.
course
.
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
.
course
))
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
.
course
)
+
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
=
time
.
time
()
+
24
*
3600
self
.
course
.
lms
.
start
=
time
.
gmtime
(
tomorrow
)
self
.
full
.
lms
.
start
=
time
.
gmtime
(
tomorrow
)
self
.
assertFalse
(
self
.
course
.
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
.
course
)
self
.
enroll
(
self
.
full
)
# shouldn't be able to get to anything except the light pages
check_non_staff
(
self
.
course
)
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
.
course
.
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
.
course
)
self
.
enroll
(
self
.
full
)
# should now be able to get to everything for self.course
check_non_staff
(
self
.
full
)
check_staff
(
self
.
course
)
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
=
time
.
time
()
+
24
*
3600
nextday
=
tomorrow
+
24
*
3600
yesterday
=
time
.
time
()
-
24
*
3600
print
"changing"
# self.course's enrollment period hasn't started
self
.
course
.
enrollment_start
=
time
.
gmtime
(
tomorrow
)
self
.
course
.
enrollment_end
=
time
.
gmtime
(
nextday
)
# full course's has
self
.
full
.
enrollment_start
=
time
.
gmtime
(
yesterday
)
self
.
full
.
enrollment_end
=
time
.
gmtime
(
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
.
course
))
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
.
course
.
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
.
course
))
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
.
course
)
self
.
assertTrue
(
self
.
try_enroll
(
self
.
course
))
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
=
time
.
time
()
+
24
*
3600
# nextday = tomorrow + 24 * 3600
# yesterday = time.time() - 24 * 3600
# toy course's hasn't started
self
.
course
.
lms
.
start
=
time
.
gmtime
(
tomorrow
)
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
=
get_user
(
self
.
student
)
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'
))
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestSubmittingProblems
(
LoginEnrollmentTestCase
):
...
...
@@ -1006,6 +477,7 @@ class TestSubmittingProblems(LoginEnrollmentTestCase):
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
):
...
...
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