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
7e52ba87
Commit
7e52ba87
authored
Oct 14, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5535 from edx/dhm/unit_perf
Performance enhancements for unit tests
parents
f3aaa4e6
3c42e8c7
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
482 additions
and
485 deletions
+482
-485
cms/djangoapps/contentstore/tests/test_contentstore.py
+432
-477
common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py
+0
-1
common/lib/xmodule/xmodule/poll_module.py
+1
-1
common/lib/xmodule/xmodule/tests/test_export.py
+49
-6
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
7e52ba87
...
...
@@ -36,7 +36,7 @@ from xmodule.modulestore.xml_exporter import export_to_xml
from
xmodule.modulestore.xml_importer
import
import_from_xml
,
perform_xlint
from
xmodule.capa_module
import
CapaDescriptor
from
xmodule.course_module
import
CourseDescriptor
from
xmodule.course_module
import
CourseDescriptor
,
Textbook
from
xmodule.seq_module
import
SequenceDescriptor
from
contentstore.utils
import
delete_course_and_groups
,
reverse_url
,
reverse_course_url
...
...
@@ -50,6 +50,7 @@ from contentstore.tests.utils import get_url
from
course_action_state.models
import
CourseRerunState
,
CourseRerunUIStateManager
from
course_action_state.managers
import
CourseActionStateItemNotFoundError
from
xmodule.contentstore.content
import
StaticContent
TEST_DATA_CONTENTSTORE
=
copy
.
deepcopy
(
settings
.
CONTENTSTORE
)
...
...
@@ -63,197 +64,10 @@ class ContentStoreTestCase(CourseTestCase):
"""
class
ContentStoreToyCourseTest
(
ContentStoreTestCase
):
class
ImportRequiredTestCases
(
ContentStoreTestCase
):
"""
Tests that rely on the toy courses.
TODO: refactor using CourseFactory so they do not.
"""
def
check_components_on_page
(
self
,
component_types
,
expected_types
):
"""
Ensure that the right types end up on the page.
component_types is the list of advanced components.
expected_types is the list of elements that should appear on the page.
expected_types and component_types should be similar, but not
exactly the same -- for example, 'video' in
component_types should cause 'Video' to be present.
Tests which legitimately need to import a course
"""
store
=
self
.
store
course_items
=
import_from_xml
(
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
course
=
course_items
[
0
]
course
.
advanced_modules
=
component_types
store
.
update_item
(
course
,
self
.
user
.
id
)
# just pick one vertical
descriptor
=
store
.
get_items
(
course
.
id
,
qualifiers
=
{
'category'
:
'vertical'
})
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
descriptor
[
0
]
.
location
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
for
expected
in
expected_types
:
self
.
assertIn
(
expected
,
resp
.
content
)
def
test_advanced_components_in_edit_unit
(
self
):
# This could be made better, but for now let's just assert that we see the advanced modules mentioned in the page
# response HTML
self
.
check_components_on_page
(
ADVANCED_COMPONENT_TYPES
,
[
'Word cloud'
,
'Annotation'
,
'Text Annotation'
,
'Video Annotation'
,
'Image Annotation'
,
'Open Response Assessment'
,
'Peer Grading Interface'
,
'split_test'
],
)
def
test_advanced_components_require_two_clicks
(
self
):
self
.
check_components_on_page
([
'word_cloud'
],
[
'Word cloud'
])
def
test_malformed_edit_unit_request
(
self
):
store
=
self
.
store
course_items
=
import_from_xml
(
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
# just pick one vertical
usage_key
=
course_items
[
0
]
.
id
.
make_usage_key
(
'vertical'
,
None
)
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
usage_key
))
self
.
assertEqual
(
resp
.
status_code
,
400
)
def
check_edit_unit
(
self
,
test_course_name
):
"""Verifies the editing HTML in all the verticals in the given test course"""
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
test_course_name
])
items
=
self
.
store
.
get_items
(
course_items
[
0
]
.
id
,
qualifiers
=
{
'category'
:
'vertical'
})
self
.
_check_verticals
(
items
)
def
test_edit_unit_toy
(
self
):
self
.
check_edit_unit
(
'toy'
)
def
_get_draft_counts
(
self
,
item
):
cnt
=
1
if
getattr
(
item
,
'is_draft'
,
False
)
else
0
for
child
in
item
.
get_children
():
cnt
=
cnt
+
self
.
_get_draft_counts
(
child
)
return
cnt
def
test_get_items
(
self
):
'''
This verifies a bug we had where the None setting in get_items() meant 'wildcard'
Unfortunately, None = published for the revision field, so get_items() would return
both draft and non-draft copies.
'''
store
=
self
.
store
course_items
=
import_from_xml
(
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
course_key
=
course_items
[
0
]
.
id
html_usage_key
=
course_key
.
make_usage_key
(
'html'
,
'test_html'
)
html_module_from_draft_store
=
store
.
get_item
(
html_usage_key
)
store
.
convert_to_draft
(
html_module_from_draft_store
.
location
,
self
.
user
.
id
)
# Query get_items() and find the html item. This should just return back a single item (not 2).
direct_store_items
=
store
.
get_items
(
course_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
html_items_from_direct_store
=
[
item
for
item
in
direct_store_items
if
(
item
.
location
==
html_usage_key
)]
self
.
assertEqual
(
len
(
html_items_from_direct_store
),
1
)
self
.
assertFalse
(
getattr
(
html_items_from_direct_store
[
0
],
'is_draft'
,
False
))
# Fetch from the draft store.
draft_store_items
=
store
.
get_items
(
course_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
draft_only
)
html_items_from_draft_store
=
[
item
for
item
in
draft_store_items
if
(
item
.
location
==
html_usage_key
)]
self
.
assertEqual
(
len
(
html_items_from_draft_store
),
1
)
self
.
assertTrue
(
getattr
(
html_items_from_draft_store
[
0
],
'is_draft'
,
False
))
def
test_draft_metadata
(
self
):
'''
This verifies a bug we had where inherited metadata was getting written to the
module as 'own-metadata' when publishing. Also verifies the metadata inheritance is
properly computed
'''
draft_store
=
self
.
store
import_from_xml
(
draft_store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
course_key
=
SlashSeparatedCourseKey
(
'edX'
,
'simple'
,
'2012_Fall'
)
html_usage_key
=
course_key
.
make_usage_key
(
'html'
,
'test_html'
)
course
=
draft_store
.
get_course
(
course_key
)
html_module
=
draft_store
.
get_item
(
html_usage_key
)
self
.
assertEqual
(
html_module
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
html_module
))
draft_store
.
convert_to_draft
(
html_module
.
location
,
self
.
user
.
id
)
# refetch to check metadata
html_module
=
draft_store
.
get_item
(
html_usage_key
)
self
.
assertEqual
(
html_module
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
html_module
))
# publish module
draft_store
.
publish
(
html_module
.
location
,
self
.
user
.
id
)
# refetch to check metadata
html_module
=
draft_store
.
get_item
(
html_usage_key
)
self
.
assertEqual
(
html_module
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
html_module
))
# put back in draft and change metadata and see if it's now marked as 'own_metadata'
draft_store
.
convert_to_draft
(
html_module
.
location
,
self
.
user
.
id
)
html_module
=
draft_store
.
get_item
(
html_usage_key
)
new_graceperiod
=
timedelta
(
hours
=
1
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
html_module
))
html_module
.
graceperiod
=
new_graceperiod
# Save the data that we've just changed to the underlying
# MongoKeyValueStore before we update the mongo datastore.
html_module
.
save
()
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
html_module
))
self
.
assertEqual
(
html_module
.
graceperiod
,
new_graceperiod
)
draft_store
.
update_item
(
html_module
,
self
.
user
.
id
)
# read back to make sure it reads as 'own-metadata'
html_module
=
draft_store
.
get_item
(
html_usage_key
)
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
html_module
))
self
.
assertEqual
(
html_module
.
graceperiod
,
new_graceperiod
)
# republish
draft_store
.
publish
(
html_module
.
location
,
self
.
user
.
id
)
# and re-read and verify 'own-metadata'
draft_store
.
convert_to_draft
(
html_module
.
location
,
self
.
user
.
id
)
html_module
=
draft_store
.
get_item
(
html_usage_key
)
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
html_module
))
self
.
assertEqual
(
html_module
.
graceperiod
,
new_graceperiod
)
def
test_get_depth_with_drafts
(
self
):
store
=
self
.
store
import_from_xml
(
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
course_key
=
SlashSeparatedCourseKey
(
'edX'
,
'simple'
,
'2012_Fall'
)
course
=
store
.
get_course
(
course_key
)
# make sure no draft items have been returned
num_drafts
=
self
.
_get_draft_counts
(
course
)
self
.
assertEqual
(
num_drafts
,
0
)
problem_usage_key
=
course_key
.
make_usage_key
(
'problem'
,
'ps01-simple'
)
problem
=
store
.
get_item
(
problem_usage_key
)
# put into draft
store
.
convert_to_draft
(
problem
.
location
,
self
.
user
.
id
)
# make sure we can query that item and verify that it is a draft
draft_problem
=
store
.
get_item
(
problem_usage_key
)
self
.
assertTrue
(
getattr
(
draft_problem
,
'is_draft'
,
False
))
# now requery with depth
course
=
store
.
get_course
(
course_key
)
# make sure just one draft item have been returned
num_drafts
=
self
.
_get_draft_counts
(
course
)
self
.
assertEqual
(
num_drafts
,
1
)
def
test_no_static_link_rewrites_on_import
(
self
):
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
course
=
course_items
[
0
]
...
...
@@ -266,87 +80,14 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
handouts
=
self
.
store
.
get_item
(
handouts_usage_key
)
self
.
assertIn
(
'/static/'
,
handouts
.
data
)
@mock.patch
(
'xmodule.course_module.requests.get'
)
def
test_import_textbook_as_content_element
(
self
,
mock_get
):
mock_get
.
return_value
.
text
=
dedent
(
"""
<?xml version="1.0"?><table_of_contents>
<entry page="5" page_label="ii" name="Table of Contents"/>
</table_of_contents>
"""
)
.
strip
()
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
course
=
self
.
store
.
get_course
(
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
))
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
def
test_import_polls
(
self
):
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
course_key
=
course_items
[
0
]
.
id
items
=
self
.
store
.
get_items
(
course_key
,
qualifiers
=
{
'category'
:
'poll_question'
})
found
=
len
(
items
)
>
0
self
.
assertTrue
(
found
)
# check that there's actually content in the 'question' field
self
.
assertGreater
(
len
(
items
[
0
]
.
question
),
0
)
def
test_xlint_fails
(
self
):
err_cnt
=
perform_xlint
(
'common/test/data'
,
[
'toy'
])
self
.
assertGreater
(
err_cnt
,
0
)
@override_settings
(
COURSES_WITH_UNSAFE_CODE
=
[
'edX/toy/.*'
])
def
test_module_preview_in_whitelist
(
self
):
"""
Tests the ajax callback to render an XModule
"""
direct_store
=
self
.
store
course_items
=
import_from_xml
(
direct_store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
usage_key
=
course_items
[
0
]
.
id
.
make_usage_key
(
'vertical'
,
'vertical_test'
)
# also try a custom response which will trigger the 'is this course in whitelist' logic
resp
=
self
.
client
.
get_json
(
get_url
(
'xblock_view_handler'
,
usage_key
,
kwargs
=
{
'view_name'
:
'container_preview'
})
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# These are the data-ids of the xblocks contained in the vertical.
self
.
assertContains
(
resp
,
'edX/toy/video/sample_video'
)
self
.
assertContains
(
resp
,
'edX/toy/video/separate_file_video'
)
self
.
assertContains
(
resp
,
'edX/toy/video/video_with_end_time'
)
self
.
assertContains
(
resp
,
'edX/toy/poll_question/T1_changemind_poll_foo_2'
)
def
test_delete
(
self
):
store
=
self
.
store
course
=
CourseFactory
.
create
()
chapterloc
=
ItemFactory
.
create
(
parent_location
=
course
.
location
,
display_name
=
"Chapter"
)
.
location
ItemFactory
.
create
(
parent_location
=
chapterloc
,
category
=
'sequential'
,
display_name
=
"Sequential"
)
sequential_key
=
course
.
id
.
make_usage_key
(
'sequential'
,
'Sequential'
)
sequential
=
store
.
get_item
(
sequential_key
)
chapter_key
=
course
.
id
.
make_usage_key
(
'chapter'
,
'Chapter'
)
chapter
=
store
.
get_item
(
chapter_key
)
# make sure the parent points to the child object which is to be deleted
self
.
assertTrue
(
sequential
.
location
in
chapter
.
children
)
self
.
client
.
delete
(
get_url
(
'xblock_handler'
,
sequential_key
))
found
=
False
try
:
store
.
get_item
(
sequential_key
)
found
=
True
except
ItemNotFoundError
:
pass
self
.
assertFalse
(
found
)
chapter
=
store
.
get_item
(
chapter_key
)
# make sure the parent no longer points to the child object which was deleted
self
.
assertFalse
(
sequential
.
location
in
chapter
.
children
)
def
test_about_overrides
(
self
):
'''
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
This test case verifies that a course can use specialized override for about data,
e.g. /about/Fall_2012/effort.html
while there is a base definition in /about/effort.html
'''
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
...
...
@@ -407,93 +148,21 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
#
# self.assertIsNotNone(thumbnail)
def
test_asset_delete_and_restore
(
self
):
'''
This test will exercise the soft delete/restore functionality of the assets
'''
content_store
,
trash_store
,
thumbnail_location
,
_location
=
self
.
_delete_asset_in_course
()
asset_location
=
AssetLocation
.
from_deprecated_string
(
'/c4x/edX/toy/asset/sample_static.txt'
)
# now try to find it in store, but they should not be there any longer
content
=
content_store
.
find
(
asset_location
,
throw_on_not_found
=
False
)
self
.
assertIsNone
(
content
)
if
thumbnail_location
:
thumbnail
=
content_store
.
find
(
thumbnail_location
,
throw_on_not_found
=
False
)
self
.
assertIsNone
(
thumbnail
)
# now try to find it and the thumbnail in trashcan - should be in there
content
=
trash_store
.
find
(
asset_location
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
content
)
if
thumbnail_location
:
thumbnail
=
trash_store
.
find
(
thumbnail_location
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
thumbnail
)
# let's restore the asset
restore_asset_from_trashcan
(
'/c4x/edX/toy/asset/sample_static.txt'
)
# now try to find it in courseware store, and they should be back after restore
content
=
content_store
.
find
(
asset_location
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
content
)
if
thumbnail_location
:
thumbnail
=
content_store
.
find
(
thumbnail_location
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
thumbnail
)
def
_delete_asset_in_course
(
self
):
"""
Helper method for:
1) importing course from xml
2) finding asset in course (verifying non-empty)
3) computing thumbnail location of asset
4) deleting the asset from the course
"""
content_store
=
contentstore
()
trash_store
=
contentstore
(
'trashcan'
)
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
content_store
)
# look up original (and thumbnail) in content store, should be there after import
location
=
AssetLocation
.
from_deprecated_string
(
'/c4x/edX/toy/asset/sample_static.txt'
)
content
=
content_store
.
find
(
location
,
throw_on_not_found
=
False
)
thumbnail_location
=
content
.
thumbnail_location
self
.
assertIsNotNone
(
content
)
#
# cdodge: temporarily comment out assertion on thumbnails because many environments
# will not have the jpeg converter installed and this test will fail
#
# self.assertIsNotNone(thumbnail_location)
# go through the website to do the delete, since the soft-delete logic is in the view
course
=
course_items
[
0
]
url
=
reverse_course_url
(
'assets_handler'
,
course
.
id
,
kwargs
=
{
'asset_key_string'
:
unicode
(
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.txt'
))}
)
resp
=
self
.
client
.
delete
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
return
content_store
,
trash_store
,
thumbnail_location
,
location
def
test_course_info_updates_import_export
(
self
):
"""
Test that course info updates are imported and exported with all content fields ('data', 'items')
"""
content_store
=
contentstore
()
data_dir
=
"common/test/data/"
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
data_dir
,
[
'course_info_updates'
],
static_content_store
=
content_store
,
verbose
=
True
)
course_id
=
SlashSeparatedCourseKey
(
'edX'
,
'course_info_updates'
,
'2014_T1'
)
course
=
self
.
store
.
get_course
(
course_id
)
courses
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
data_dir
,
[
'course_info_updates'
],
static_content_store
=
content_store
,
verbose
=
True
,
)
course
=
courses
[
0
]
self
.
assertIsNotNone
(
course
)
course_updates
=
self
.
store
.
get_item
(
course_id
.
make_usage_key
(
'course_info'
,
'updates'
))
course_updates
=
self
.
store
.
get_item
(
course
.
id
.
make_usage_key
(
'course_info'
,
'updates'
))
self
.
assertIsNotNone
(
course_updates
)
# check that course which is imported has files 'updates.html' and 'updates.items.json'
...
...
@@ -516,7 +185,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
# with same content as in course 'info' directory
root_dir
=
path
(
mkdtemp_clean
())
print
'Exporting to tempdir = {0}'
.
format
(
root_dir
)
export_to_xml
(
self
.
store
,
content_store
,
course
_
id
,
root_dir
,
'test_export'
)
export_to_xml
(
self
.
store
,
content_store
,
course
.
id
,
root_dir
,
'test_export'
)
# check that exported course has files 'updates.html' and 'updates.items.json'
filesystem
=
OSFS
(
root_dir
/
'test_export/info'
)
...
...
@@ -532,61 +201,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
on_disk
=
loads
(
grading_policy
.
read
())
self
.
assertEqual
(
on_disk
,
course_updates
.
items
)
def
test_empty_trashcan
(
self
):
'''
This test will exercise the emptying of the asset trashcan
'''
__
,
trash_store
,
__
,
_location
=
self
.
_delete_asset_in_course
()
# make sure there's something in the trashcan
course_id
=
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'6.002_Spring_2012'
)
all_assets
,
__
=
trash_store
.
get_all_content_for_course
(
course_id
)
self
.
assertGreater
(
len
(
all_assets
),
0
)
# make sure we have some thumbnails in our trashcan
_all_thumbnails
=
trash_store
.
get_all_content_thumbnails_for_course
(
course_id
)
#
# cdodge: temporarily comment out assertion on thumbnails because many environments
# will not have the jpeg converter installed and this test will fail
#
# self.assertGreater(len(all_thumbnails), 0)
# empty the trashcan
empty_asset_trashcan
([
course_id
])
# make sure trashcan is empty
all_assets
,
count
=
trash_store
.
get_all_content_for_course
(
course_id
)
self
.
assertEqual
(
len
(
all_assets
),
0
)
self
.
assertEqual
(
count
,
0
)
all_thumbnails
=
trash_store
.
get_all_content_thumbnails_for_course
(
course_id
)
self
.
assertEqual
(
len
(
all_thumbnails
),
0
)
def
test_illegal_draft_crud_ops
(
self
):
draft_store
=
self
.
store
course
=
CourseFactory
.
create
()
location
=
course
.
id
.
make_usage_key
(
'chapter'
,
'neuvo'
)
# Ensure draft mongo store does not create drafts for things that shouldn't be draft
newobject
=
draft_store
.
create_item
(
self
.
user
.
id
,
location
.
course_key
,
location
.
block_type
,
location
.
block_id
)
self
.
assertFalse
(
getattr
(
newobject
,
'is_draft'
,
False
))
with
self
.
assertRaises
(
InvalidVersionError
):
draft_store
.
convert_to_draft
(
location
,
self
.
user
.
id
)
chapter
=
draft_store
.
get_item
(
location
)
chapter
.
data
=
'chapter data'
draft_store
.
update_item
(
chapter
,
self
.
user
.
id
)
newobject
=
draft_store
.
get_item
(
chapter
.
location
)
self
.
assertFalse
(
getattr
(
newobject
,
'is_draft'
,
False
))
with
self
.
assertRaises
(
InvalidVersionError
):
draft_store
.
unpublish
(
location
,
self
.
user
.
id
)
def
test_bad_contentstore_request
(
self
):
resp
=
self
.
client
.
get_html
(
'http://localhost:8001/c4x/CDX/123123/asset/&images_circuits_Lab7Solution2.png'
)
self
.
assertEqual
(
resp
.
status_code
,
400
)
def
test_rewrite_nonportable_links_on_import
(
self
):
content_store
=
contentstore
()
...
...
@@ -603,35 +217,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
html_module
=
self
.
store
.
get_item
(
html_module_location
)
self
.
assertIn
(
'/jump_to_id/nonportable_link'
,
html_module
.
data
)
def
test_delete_course
(
self
):
"""
This test will import a course, make a draft item, and delete it. This will also assert that the
draft content is also deleted
"""
content_store
=
contentstore
()
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
content_store
)
course_id
=
course_items
[
0
]
.
id
# get a vertical (and components in it) to put into DRAFT
vertical
=
self
.
store
.
get_item
(
course_id
.
make_usage_key
(
'vertical'
,
'vertical_test'
),
depth
=
1
)
self
.
store
.
convert_to_draft
(
vertical
.
location
,
self
.
user
.
id
)
# delete the course
self
.
store
.
delete_course
(
course_id
,
self
.
user
.
id
)
# assert that there's absolutely no non-draft modules in the course
# this should also include all draft items
items
=
self
.
store
.
get_items
(
course_id
)
self
.
assertEqual
(
len
(
items
),
0
)
# assert that all content in the asset library is also deleted
assets
,
count
=
content_store
.
get_all_content_for_course
(
course_id
)
self
.
assertEqual
(
len
(
assets
),
0
)
self
.
assertEqual
(
count
,
0
)
def
verify_content_existence
(
self
,
store
,
root_dir
,
course_id
,
dirname
,
category_name
,
filename_suffix
=
''
):
filesystem
=
OSFS
(
root_dir
/
'test_export'
)
self
.
assertTrue
(
filesystem
.
exists
(
dirname
))
...
...
@@ -835,51 +420,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
html_module
=
self
.
store
.
get_item
(
course_id
.
make_usage_key
(
'html'
,
'just_img'
))
self
.
assertIn
(
'<img src="/static/foo_bar.jpg" />'
,
html_module
.
data
)
def
test_course_handouts_rewrites
(
self
):
# import a test course
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
course_id
=
course_items
[
0
]
.
id
handouts_location
=
course_id
.
make_usage_key
(
'course_info'
,
'handouts'
)
# get module info (json)
resp
=
self
.
client
.
get
(
get_url
(
'xblock_handler'
,
handouts_location
))
# make sure we got a successful response
self
.
assertEqual
(
resp
.
status_code
,
200
)
# check that /static/ has been converted to the full path
# note, we know the link it should be because that's what in the 'toy' course in the test data
self
.
assertContains
(
resp
,
'/c4x/edX/toy/asset/handouts_sample_handout.txt'
)
def
test_prefetch_children
(
self
):
mongo_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
mongo
)
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
])
course_id
=
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
)
# make sure we haven't done too many round trips to DB
# note we say 4 round trips here for:
# 1) to get the run id
# 2) the course,
# 3 & 4) for the chapters and sequentials
# Because we're querying from the top of the tree, we cache information needed for inheritance,
# so we don't need to make an extra query to compute it.
# set the branch to 'publish' in order to prevent extra lookups of draft versions
with
mongo_store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
with
check_mongo_calls
(
4
,
0
):
course
=
mongo_store
.
get_course
(
course_id
,
depth
=
2
)
# make sure we pre-fetched a known sequential which should be at depth=2
self
.
assertTrue
(
course_id
.
make_usage_key
(
'sequential'
,
'vertical_sequential'
)
in
course
.
system
.
module_data
)
# make sure we don't have a specific vertical which should be at depth=3
self
.
assertFalse
(
course_id
.
make_usage_key
(
'vertical'
,
'vertical_test'
)
in
course
.
system
.
module_data
)
# Now, test with the branch set to draft. No extra round trips b/c it doesn't go deep enough to get
# beyond direct only categories
with
mongo_store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
check_mongo_calls
(
4
,
0
):
mongo_store
.
get_course
(
course_id
,
depth
=
2
)
def
test_export_course_without_content_store
(
self
):
# Create toy course
...
...
@@ -912,12 +452,427 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
)
self
.
assertEqual
(
len
(
items
),
1
)
def
_check_verticals
(
self
,
items
):
class
MiscCourseTests
(
ContentStoreTestCase
):
"""
Tests that rely on the toy courses.
"""
def
setUp
(
self
):
super
(
MiscCourseTests
,
self
)
.
setUp
()
# save locs not items b/c the items won't have the subsequently created children in them until refetched
self
.
chapter_loc
=
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
course
.
location
,
'chapter'
,
'test_chapter'
)
.
location
self
.
seq_loc
=
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
chapter_loc
,
'sequential'
,
'test_seq'
)
.
location
self
.
vert_loc
=
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
seq_loc
,
'vertical'
,
'test_vert'
)
.
location
# now create some things quasi like the toy course had
self
.
problem
=
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
vert_loc
,
'problem'
,
'test_problem'
,
fields
=
{
"data"
:
"<problem>Test</problem>"
}
)
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
vert_loc
,
'video'
,
fields
=
{
"youtube_id_0_75"
:
"JMD_ifUUfsU"
,
"youtube_id_1_0"
:
"OEoXaMPEzfM"
,
"youtube_id_1_25"
:
"AKqURZnYqpk"
,
"youtube_id_1_5"
:
"DYpADpL7jAY"
,
"name"
:
"sample_video"
,
}
)
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
vert_loc
,
'video'
,
fields
=
{
"youtube_id_0_75"
:
"JMD_ifUUfsU"
,
"youtube_id_1_0"
:
"OEoXaMPEzfM"
,
"youtube_id_1_25"
:
"AKqURZnYqpk"
,
"youtube_id_1_5"
:
"DYpADpL7jAY"
,
"name"
:
"truncated_video"
,
"end_time"
:
10.0
,
}
)
self
.
store
.
create_child
(
self
.
user
.
id
,
self
.
vert_loc
,
'poll_question'
,
fields
=
{
"name"
:
"T1_changemind_poll_foo_2"
,
"display_name"
:
"Change your answer"
,
"reset"
:
False
,
"question"
:
"Have you changed your mind?"
,
"answers"
:
[{
"id"
:
"yes"
,
"text"
:
"Yes"
},
{
"id"
:
"no"
,
"text"
:
"No"
}],
}
)
self
.
course
=
self
.
store
.
publish
(
self
.
course
.
location
,
self
.
user
.
id
)
def
check_components_on_page
(
self
,
component_types
,
expected_types
):
"""
Ensure that the right types end up on the page.
component_types is the list of advanced components.
expected_types is the list of elements that should appear on the page.
expected_types and component_types should be similar, but not
exactly the same -- for example, 'video' in
component_types should cause 'Video' to be present.
"""
self
.
course
.
advanced_modules
=
component_types
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
# just pick one vertical
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
self
.
vert_loc
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
for
expected
in
expected_types
:
self
.
assertIn
(
expected
,
resp
.
content
)
def
test_advanced_components_in_edit_unit
(
self
):
# This could be made better, but for now let's just assert that we see the advanced modules mentioned in the page
# response HTML
self
.
check_components_on_page
(
ADVANCED_COMPONENT_TYPES
,
[
'Word cloud'
,
'Annotation'
,
'Text Annotation'
,
'Video Annotation'
,
'Image Annotation'
,
'Open Response Assessment'
,
'Peer Grading Interface'
,
'split_test'
],
)
def
test_advanced_components_require_two_clicks
(
self
):
self
.
check_components_on_page
([
'word_cloud'
],
[
'Word cloud'
])
def
test_malformed_edit_unit_request
(
self
):
# just pick one vertical
usage_key
=
self
.
course
.
id
.
make_usage_key
(
'vertical'
,
None
)
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
usage_key
))
self
.
assertEqual
(
resp
.
status_code
,
400
)
def
test_edit_unit
(
self
):
"""Verifies rendering the editor in all the verticals in the given test course"""
self
.
_check_verticals
([
self
.
vert_loc
])
def
_get_draft_counts
(
self
,
item
):
cnt
=
1
if
getattr
(
item
,
'is_draft'
,
False
)
else
0
for
child
in
item
.
get_children
():
cnt
=
cnt
+
self
.
_get_draft_counts
(
child
)
return
cnt
def
test_get_items
(
self
):
'''
This verifies a bug we had where the None setting in get_items() meant 'wildcard'
Unfortunately, None = published for the revision field, so get_items() would return
both draft and non-draft copies.
'''
self
.
store
.
convert_to_draft
(
self
.
problem
.
location
,
self
.
user
.
id
)
# Query get_items() and find the html item. This should just return back a single item (not 2).
direct_store_items
=
self
.
store
.
get_items
(
self
.
course
.
id
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
items_from_direct_store
=
[
item
for
item
in
direct_store_items
if
(
item
.
location
==
self
.
problem
.
location
)]
self
.
assertEqual
(
len
(
items_from_direct_store
),
1
)
self
.
assertFalse
(
getattr
(
items_from_direct_store
[
0
],
'is_draft'
,
False
))
# Fetch from the draft store.
draft_store_items
=
self
.
store
.
get_items
(
self
.
course
.
id
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
draft_only
)
items_from_draft_store
=
[
item
for
item
in
draft_store_items
if
(
item
.
location
==
self
.
problem
.
location
)]
self
.
assertEqual
(
len
(
items_from_draft_store
),
1
)
# TODO the below won't work for split mongo
self
.
assertTrue
(
getattr
(
items_from_draft_store
[
0
],
'is_draft'
,
False
))
def
test_draft_metadata
(
self
):
'''
This verifies a bug we had where inherited metadata was getting written to the
module as 'own-metadata' when publishing. Also verifies the metadata inheritance is
properly computed
'''
# refetch course so it has all the children correct
course
=
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
course
.
graceperiod
=
timedelta
(
days
=
1
,
hours
=
5
,
minutes
=
59
,
seconds
=
59
)
course
=
self
.
store
.
update_item
(
course
,
self
.
user
.
id
)
problem
=
self
.
store
.
get_item
(
self
.
problem
.
location
)
self
.
assertEqual
(
problem
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
problem
))
self
.
store
.
convert_to_draft
(
problem
.
location
,
self
.
user
.
id
)
# refetch to check metadata
problem
=
self
.
store
.
get_item
(
problem
.
location
)
self
.
assertEqual
(
problem
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
problem
))
# publish module
self
.
store
.
publish
(
problem
.
location
,
self
.
user
.
id
)
# refetch to check metadata
problem
=
self
.
store
.
get_item
(
problem
.
location
)
self
.
assertEqual
(
problem
.
graceperiod
,
course
.
graceperiod
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
problem
))
# put back in draft and change metadata and see if it's now marked as 'own_metadata'
self
.
store
.
convert_to_draft
(
problem
.
location
,
self
.
user
.
id
)
problem
=
self
.
store
.
get_item
(
problem
.
location
)
new_graceperiod
=
timedelta
(
hours
=
1
)
self
.
assertNotIn
(
'graceperiod'
,
own_metadata
(
problem
))
problem
.
graceperiod
=
new_graceperiod
# Save the data that we've just changed to the underlying
# MongoKeyValueStore before we update the mongo datastore.
problem
.
save
()
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
problem
))
self
.
assertEqual
(
problem
.
graceperiod
,
new_graceperiod
)
self
.
store
.
update_item
(
problem
,
self
.
user
.
id
)
# read back to make sure it reads as 'own-metadata'
problem
=
self
.
store
.
get_item
(
problem
.
location
)
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
problem
))
self
.
assertEqual
(
problem
.
graceperiod
,
new_graceperiod
)
# republish
self
.
store
.
publish
(
problem
.
location
,
self
.
user
.
id
)
# and re-read and verify 'own-metadata'
self
.
store
.
convert_to_draft
(
problem
.
location
,
self
.
user
.
id
)
problem
=
self
.
store
.
get_item
(
problem
.
location
)
self
.
assertIn
(
'graceperiod'
,
own_metadata
(
problem
))
self
.
assertEqual
(
problem
.
graceperiod
,
new_graceperiod
)
def
test_get_depth_with_drafts
(
self
):
# make sure no draft items have been returned
num_drafts
=
self
.
_get_draft_counts
(
self
.
course
)
self
.
assertEqual
(
num_drafts
,
0
)
# put into draft
self
.
store
.
convert_to_draft
(
self
.
problem
.
location
,
self
.
user
.
id
)
# make sure we can query that item and verify that it is a draft
draft_problem
=
self
.
store
.
get_item
(
self
.
problem
.
location
)
self
.
assertTrue
(
getattr
(
draft_problem
,
'is_draft'
,
False
))
# now requery with depth
course
=
self
.
store
.
get_course
(
self
.
course
.
id
,
depth
=
None
)
# make sure just one draft item have been returned
num_drafts
=
self
.
_get_draft_counts
(
course
)
self
.
assertEqual
(
num_drafts
,
1
)
@mock.patch
(
'xmodule.course_module.requests.get'
)
def
test_import_textbook_as_content_element
(
self
,
mock_get
):
mock_get
.
return_value
.
text
=
dedent
(
"""
<?xml version="1.0"?><table_of_contents>
<entry page="5" page_label="ii" name="Table of Contents"/>
</table_of_contents>
"""
)
.
strip
()
self
.
course
.
textbooks
=
[
Textbook
(
"Textbook"
,
"https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"
)]
course
=
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
self
.
assertGreater
(
len
(
course
.
textbooks
),
0
)
def
test_import_polls
(
self
):
items
=
self
.
store
.
get_items
(
self
.
course
.
id
,
qualifiers
=
{
'category'
:
'poll_question'
})
self
.
assertTrue
(
len
(
items
)
>
0
)
# check that there's actually content in the 'question' field
self
.
assertGreater
(
len
(
items
[
0
]
.
question
),
0
)
def
test_module_preview_in_whitelist
(
self
):
"""
Tests the ajax callback to render an XModule
"""
with
override_settings
(
COURSES_WITH_UNSAFE_CODE
=
[
unicode
(
self
.
course
.
id
)]):
# also try a custom response which will trigger the 'is this course in whitelist' logic
resp
=
self
.
client
.
get_json
(
get_url
(
'xblock_view_handler'
,
self
.
vert_loc
,
kwargs
=
{
'view_name'
:
'container_preview'
})
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
vertical
=
self
.
store
.
get_item
(
self
.
vert_loc
)
for
child
in
vertical
.
children
:
self
.
assertContains
(
resp
,
unicode
(
child
))
def
test_delete
(
self
):
# make sure the parent points to the child object which is to be deleted
# need to refetch chapter b/c at the time it was assigned it had no children
chapter
=
self
.
store
.
get_item
(
self
.
chapter_loc
)
self
.
assertIn
(
self
.
seq_loc
,
chapter
.
children
)
self
.
client
.
delete
(
get_url
(
'xblock_handler'
,
self
.
seq_loc
))
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_item
(
self
.
seq_loc
)
chapter
=
self
.
store
.
get_item
(
self
.
chapter_loc
)
# make sure the parent no longer points to the child object which was deleted
self
.
assertNotIn
(
self
.
seq_loc
,
chapter
.
children
)
def
test_asset_delete_and_restore
(
self
):
'''
This test will exercise the soft delete/restore functionality of the assets
'''
asset_key
=
self
.
_delete_asset_in_course
()
# now try to find it in store, but they should not be there any longer
content
=
contentstore
()
.
find
(
asset_key
,
throw_on_not_found
=
False
)
self
.
assertIsNone
(
content
)
# now try to find it and the thumbnail in trashcan - should be in there
content
=
contentstore
(
'trashcan'
)
.
find
(
asset_key
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
content
)
# let's restore the asset
restore_asset_from_trashcan
(
unicode
(
asset_key
))
# now try to find it in courseware store, and they should be back after restore
content
=
contentstore
(
'trashcan'
)
.
find
(
asset_key
,
throw_on_not_found
=
False
)
self
.
assertIsNotNone
(
content
)
def
_delete_asset_in_course
(
self
):
"""
Helper method for:
1) importing course from xml
2) finding asset in course (verifying non-empty)
3) computing thumbnail location of asset
4) deleting the asset from the course
"""
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.txt'
)
content
=
StaticContent
(
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
)
contentstore
()
.
save
(
content
)
# go through the website to do the delete, since the soft-delete logic is in the view
url
=
reverse_course_url
(
'assets_handler'
,
self
.
course
.
id
,
kwargs
=
{
'asset_key_string'
:
unicode
(
asset_key
)}
)
resp
=
self
.
client
.
delete
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
return
asset_key
def
test_empty_trashcan
(
self
):
'''
This test will exercise the emptying of the asset trashcan
'''
self
.
_delete_asset_in_course
()
# make sure there's something in the trashcan
all_assets
,
__
=
contentstore
(
'trashcan'
)
.
get_all_content_for_course
(
self
.
course
.
id
)
self
.
assertGreater
(
len
(
all_assets
),
0
)
# empty the trashcan
empty_asset_trashcan
([
self
.
course
.
id
])
# make sure trashcan is empty
all_assets
,
count
=
contentstore
(
'trashcan'
)
.
get_all_content_for_course
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
all_assets
),
0
)
self
.
assertEqual
(
count
,
0
)
def
test_illegal_draft_crud_ops
(
self
):
# this test presumes old mongo and split_draft not full split
with
self
.
assertRaises
(
InvalidVersionError
):
self
.
store
.
convert_to_draft
(
self
.
chapter_loc
,
self
.
user
.
id
)
chapter
=
self
.
store
.
get_item
(
self
.
chapter_loc
)
chapter
.
data
=
'chapter data'
self
.
store
.
update_item
(
chapter
,
self
.
user
.
id
)
newobject
=
self
.
store
.
get_item
(
self
.
chapter_loc
)
self
.
assertFalse
(
getattr
(
newobject
,
'is_draft'
,
False
))
with
self
.
assertRaises
(
InvalidVersionError
):
self
.
store
.
unpublish
(
self
.
chapter_loc
,
self
.
user
.
id
)
def
test_bad_contentstore_request
(
self
):
resp
=
self
.
client
.
get_html
(
'http://localhost:8001/c4x/CDX/123123/asset/&images_circuits_Lab7Solution2.png'
)
self
.
assertEqual
(
resp
.
status_code
,
400
)
def
test_delete_course
(
self
):
"""
This test creates a course, makes a draft item, and deletes the course. This will also assert that the
draft content is also deleted
"""
# add an asset
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.txt'
)
content
=
StaticContent
(
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
)
contentstore
()
.
save
(
content
)
assets
,
count
=
contentstore
()
.
get_all_content_for_course
(
self
.
course
.
id
)
self
.
assertGreater
(
len
(
assets
),
0
)
self
.
assertGreater
(
count
,
0
)
self
.
store
.
convert_to_draft
(
self
.
vert_loc
,
self
.
user
.
id
)
# delete the course
self
.
store
.
delete_course
(
self
.
course
.
id
,
self
.
user
.
id
)
# assert that there's absolutely no non-draft modules in the course
# this should also include all draft items
items
=
self
.
store
.
get_items
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
items
),
0
)
# assert that all content in the asset library is also deleted
assets
,
count
=
contentstore
()
.
get_all_content_for_course
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
assets
),
0
)
self
.
assertEqual
(
count
,
0
)
def
test_course_handouts_rewrites
(
self
):
"""
Test that the xblock_handler rewrites static handout links
"""
handouts
=
self
.
store
.
create_item
(
self
.
user
.
id
,
self
.
course
.
id
,
'course_info'
,
'handouts'
,
fields
=
{
"data"
:
"<a href='/static/handouts/sample_handout.txt'>Sample</a>"
,
}
)
# get module info (json)
resp
=
self
.
client
.
get
(
get_url
(
'xblock_handler'
,
handouts
.
location
))
# make sure we got a successful response
self
.
assertEqual
(
resp
.
status_code
,
200
)
# check that /static/ has been converted to the full path
# note, we know the link it should be because that's what in the 'toy' course in the test data
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'handouts_sample_handout.txt'
)
self
.
assertContains
(
resp
,
unicode
(
asset_key
))
def
test_prefetch_children
(
self
):
# make sure we haven't done too many round trips to DB
# note we say 4 round trips here for:
# 1) the course,
# 2 & 3) for the chapters and sequentials
# Because we're querying from the top of the tree, we cache information needed for inheritance,
# so we don't need to make an extra query to compute it.
# set the branch to 'publish' in order to prevent extra lookups of draft versions
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
,
self
.
course
.
id
):
with
check_mongo_calls
(
3
,
0
):
course
=
self
.
store
.
get_course
(
self
.
course
.
id
,
depth
=
2
)
# make sure we pre-fetched a known sequential which should be at depth=2
self
.
assertIn
(
self
.
seq_loc
,
course
.
system
.
module_data
)
# make sure we don't have a specific vertical which should be at depth=3
self
.
assertNotIn
(
self
.
vert_loc
,
course
.
system
.
module_data
)
# Now, test with the branch set to draft. No extra round trips b/c it doesn't go deep enough to get
# beyond direct only categories
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
self
.
course
.
id
):
with
check_mongo_calls
(
3
,
0
):
self
.
store
.
get_course
(
self
.
course
.
id
,
depth
=
2
)
def
_check_verticals
(
self
,
locations
):
""" Test getting the editing HTML for each vertical. """
# Assert is here to make sure that the course being tested actually has verticals (units) to check.
self
.
assertGreater
(
len
(
item
s
),
0
)
for
descriptor
in
item
s
:
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
descriptor
.
location
))
self
.
assertGreater
(
len
(
location
s
),
0
)
for
loc
in
location
s
:
resp
=
self
.
client
.
get_html
(
get_url
(
'container_handler'
,
loc
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py
View file @
7e52ba87
"""
Test contentstore.mongo functionality
"""
import
os
import
logging
from
uuid
import
uuid4
import
unittest
...
...
common/lib/xmodule/xmodule/poll_module.py
View file @
7e52ba87
...
...
@@ -30,7 +30,7 @@ class PollFields(object):
voted
=
Boolean
(
help
=
"Whether this student has voted on the poll"
,
scope
=
Scope
.
user_state
,
default
=
False
)
poll_answer
=
String
(
help
=
"Student answer"
,
scope
=
Scope
.
user_state
,
default
=
''
)
poll_answers
=
Dict
(
help
=
"
All possible answers for the poll fro other
students"
,
scope
=
Scope
.
user_state_summary
)
poll_answers
=
Dict
(
help
=
"
Poll answers from all
students"
,
scope
=
Scope
.
user_state_summary
)
# List of answers, in the form {'id': 'some id', 'text': 'the answer text'}
answers
=
List
(
help
=
"Poll answers from xml"
,
scope
=
Scope
.
content
,
default
=
[])
...
...
common/lib/xmodule/xmodule/tests/test_export.py
View file @
7e52ba87
...
...
@@ -230,12 +230,55 @@ class ConvertExportFormat(unittest.TestCase):
# Expand all the test archives and store their paths.
self
.
data_dir
=
path
(
__file__
)
.
realpath
()
.
parent
/
'data'
self
.
version0_nodrafts
=
self
.
_expand_archive
(
'Version0_nodrafts.tar.gz'
)
self
.
version1_nodrafts
=
self
.
_expand_archive
(
'Version1_nodrafts.tar.gz'
)
self
.
version0_drafts
=
self
.
_expand_archive
(
'Version0_drafts.tar.gz'
)
self
.
version1_drafts
=
self
.
_expand_archive
(
'Version1_drafts.tar.gz'
)
self
.
version1_drafts_extra_branch
=
self
.
_expand_archive
(
'Version1_drafts_extra_branch.tar.gz'
)
self
.
no_version
=
self
.
_expand_archive
(
'NoVersionNumber.tar.gz'
)
self
.
_version0_nodrafts
=
None
self
.
_version1_nodrafts
=
None
self
.
_version0_drafts
=
None
self
.
_version1_drafts
=
None
self
.
_version1_drafts_extra_branch
=
None
self
.
_no_version
=
None
@property
def
version0_nodrafts
(
self
):
"lazily expand this"
if
self
.
_version0_nodrafts
is
None
:
self
.
_version0_nodrafts
=
self
.
_expand_archive
(
'Version0_nodrafts.tar.gz'
)
return
self
.
_version0_nodrafts
@property
def
version1_nodrafts
(
self
):
"lazily expand this"
if
self
.
_version1_nodrafts
is
None
:
self
.
_version1_nodrafts
=
self
.
_expand_archive
(
'Version1_nodrafts.tar.gz'
)
return
self
.
_version1_nodrafts
@property
def
version0_drafts
(
self
):
"lazily expand this"
if
self
.
_version0_drafts
is
None
:
self
.
_version0_drafts
=
self
.
_expand_archive
(
'Version0_drafts.tar.gz'
)
return
self
.
_version0_drafts
@property
def
version1_drafts
(
self
):
"lazily expand this"
if
self
.
_version1_drafts
is
None
:
self
.
_version1_drafts
=
self
.
_expand_archive
(
'Version1_drafts.tar.gz'
)
return
self
.
_version1_drafts
@property
def
version1_drafts_extra_branch
(
self
):
"lazily expand this"
if
self
.
_version1_drafts_extra_branch
is
None
:
self
.
_version1_drafts_extra_branch
=
self
.
_expand_archive
(
'Version1_drafts_extra_branch.tar.gz'
)
return
self
.
_version1_drafts_extra_branch
@property
def
no_version
(
self
):
"lazily expand this"
if
self
.
_no_version
is
None
:
self
.
_no_version
=
self
.
_expand_archive
(
'NoVersionNumber.tar.gz'
)
return
self
.
_no_version
def
tearDown
(
self
):
""" Common cleanup. """
...
...
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