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
e65730b9
Commit
e65730b9
authored
Sep 30, 2015
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rationalize all cases around direct-only categories (both as blocks and parents) and delete
parent
ac507c3d
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
390 additions
and
144 deletions
+390
-144
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+2
-2
common/lib/xmodule/xmodule/modulestore/split_mongo/split_draft.py
+21
-22
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
+176
-61
common/lib/xmodule/xmodule/modulestore/tests/test_publish.py
+0
-26
common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py
+191
-33
No files found.
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
e65730b9
...
@@ -3036,9 +3036,9 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
...
@@ -3036,9 +3036,9 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
Delete the orphan and any of its descendants which no longer have parents.
Delete the orphan and any of its descendants which no longer have parents.
"""
"""
if
len
(
self
.
_get_parents_from_structure
(
orphan
,
structure
))
==
0
:
if
len
(
self
.
_get_parents_from_structure
(
orphan
,
structure
))
==
0
:
for
child
in
structure
[
'blocks'
][
orphan
]
.
fields
.
get
(
'children'
,
[]):
orphan_data
=
structure
[
'blocks'
]
.
pop
(
orphan
)
for
child
in
orphan_data
.
fields
.
get
(
'children'
,
[]):
self
.
_delete_if_true_orphan
(
BlockKey
(
*
child
),
structure
)
self
.
_delete_if_true_orphan
(
BlockKey
(
*
child
),
structure
)
del
structure
[
'blocks'
][
orphan
]
@contract
(
returns
=
BlockData
)
@contract
(
returns
=
BlockData
)
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
,
raw
=
False
,
block_defaults
=
None
):
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
,
raw
=
False
,
block_defaults
=
None
):
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split_draft.py
View file @
e65730b9
...
@@ -189,41 +189,40 @@ class DraftVersioningModuleStore(SplitMongoModuleStore, ModuleStoreDraftAndPubli
...
@@ -189,41 +189,40 @@ class DraftVersioningModuleStore(SplitMongoModuleStore, ModuleStoreDraftAndPubli
currently only provided by contentstore.views.item.orphan_handler
currently only provided by contentstore.views.item.orphan_handler
Otherwise, raises a ValueError.
Otherwise, raises a ValueError.
"""
"""
allowed_revisions
=
[
None
,
ModuleStoreEnum
.
RevisionOption
.
published_only
,
ModuleStoreEnum
.
RevisionOption
.
all
]
if
revision
not
in
allowed_revisions
:
raise
UnsupportedRevisionError
(
allowed_revisions
)
autopublish_parent
=
False
with
self
.
bulk_operations
(
location
.
course_key
):
with
self
.
bulk_operations
(
location
.
course_key
):
if
isinstance
(
location
,
LibraryUsageLocator
):
if
isinstance
(
location
,
LibraryUsageLocator
):
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
library
]
# Libraries don't yet have draft/publish support
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
library
]
# Libraries don't yet have draft/publish support
elif
revision
==
ModuleStoreEnum
.
RevisionOption
.
published_only
:
elif
location
.
category
in
DIRECT_ONLY_CATEGORIES
:
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
published
]
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
published
,
ModuleStoreEnum
.
BranchName
.
draft
]
elif
revision
==
ModuleStoreEnum
.
RevisionOption
.
all
:
elif
revision
==
ModuleStoreEnum
.
RevisionOption
.
all
:
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
published
,
ModuleStoreEnum
.
BranchName
.
draft
]
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
published
,
ModuleStoreEnum
.
BranchName
.
draft
]
else
:
if
revision
==
ModuleStoreEnum
.
RevisionOption
.
published_only
:
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
published
]
elif
revision
is
None
:
elif
revision
is
None
:
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
draft
]
branches_to_delete
=
[
ModuleStoreEnum
.
BranchName
.
draft
]
parent_loc
=
self
.
get_parent_location
(
location
.
for_branch
(
ModuleStoreEnum
.
BranchName
.
draft
))
if
location
.
category
in
DIRECT_ONLY_CATEGORIES
:
autopublish_parent
=
(
branches_to_delete
.
append
(
ModuleStoreEnum
.
BranchName
.
published
)
not
skip_auto_publish
and
else
:
parent_loc
is
not
None
and
raise
UnsupportedRevisionError
(
parent_loc
.
block_type
in
DIRECT_ONLY_CATEGORIES
[
None
,
ModuleStoreEnum
.
RevisionOption
.
published_only
,
ModuleStoreEnum
.
RevisionOption
.
all
]
)
)
self
.
_flag_publish_event
(
location
.
course_key
)
self
.
_flag_publish_event
(
location
.
course_key
)
for
branch
in
branches_to_delete
:
for
branch
in
branches_to_delete
:
branched_location
=
location
.
for_branch
(
branch
)
branched_location
=
location
.
for_branch
(
branch
)
parent_loc
=
self
.
get_parent_location
(
branched_location
)
super
(
DraftVersioningModuleStore
,
self
)
.
delete_item
(
branched_location
,
user_id
)
super
(
DraftVersioningModuleStore
,
self
)
.
delete_item
(
branched_location
,
user_id
)
# publish parent w/o child if deleted element is direct only (not based on type of parent)
# publish vertical to behave more like the old mongo/draft modulestore - TNL-2593
if
autopublish_parent
:
if
(
branch
==
ModuleStoreEnum
.
BranchName
.
draft
and
branched_location
.
block_type
in
(
DIRECT_ONLY_CATEGORIES
+
[
'vertical'
])
and
parent_loc
and
not
skip_auto_publish
):
# will publish if its not an orphan
self
.
publish
(
parent_loc
.
version_agnostic
(),
user_id
,
blacklist
=
EXCLUDE_ALL
,
**
kwargs
)
self
.
publish
(
parent_loc
.
version_agnostic
(),
user_id
,
blacklist
=
EXCLUDE_ALL
,
**
kwargs
)
def
_map_revision_to_branch
(
self
,
key
,
revision
=
None
):
def
_map_revision_to_branch
(
self
,
key
,
revision
=
None
):
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
View file @
e65730b9
...
@@ -91,19 +91,19 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
...
@@ -91,19 +91,19 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
OPTIONS
=
{
OPTIONS
=
{
'stores'
:
[
'stores'
:
[
{
{
'NAME'
:
'draft'
,
'NAME'
:
ModuleStoreEnum
.
Type
.
mongo
,
'ENGINE'
:
'xmodule.modulestore.mongo.draft.DraftModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.mongo.draft.DraftModuleStore'
,
'DOC_STORE_CONFIG'
:
DOC_STORE_CONFIG
,
'DOC_STORE_CONFIG'
:
DOC_STORE_CONFIG
,
'OPTIONS'
:
modulestore_options
'OPTIONS'
:
modulestore_options
},
},
{
{
'NAME'
:
'split'
,
'NAME'
:
ModuleStoreEnum
.
Type
.
split
,
'ENGINE'
:
'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore'
,
'DOC_STORE_CONFIG'
:
DOC_STORE_CONFIG
,
'DOC_STORE_CONFIG'
:
DOC_STORE_CONFIG
,
'OPTIONS'
:
modulestore_options
'OPTIONS'
:
modulestore_options
},
},
{
{
'NAME'
:
'xml'
,
'NAME'
:
ModuleStoreEnum
.
Type
.
xml
,
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
'OPTIONS'
:
{
'OPTIONS'
:
{
'data_dir'
:
DATA_DIR
,
'data_dir'
:
DATA_DIR
,
...
@@ -289,8 +289,11 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
...
@@ -289,8 +289,11 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
self
.
xml_chapter_location
=
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
replace
(
self
.
xml_chapter_location
=
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
replace
(
category
=
'chapter'
,
name
=
'Overview'
category
=
'chapter'
,
name
=
'Overview'
)
)
self
.
_create_course
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
_create_course
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
assertEquals
(
default
,
self
.
store
.
get_modulestore_type
(
self
.
course
.
id
))
@ddt.ddt
@ddt.ddt
@attr
(
'mongo'
)
@attr
(
'mongo'
)
...
@@ -298,7 +301,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -298,7 +301,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
"""
"""
Tests of the MixedModulestore interface methods.
Tests of the MixedModulestore interface methods.
"""
"""
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_get_modulestore_type
(
self
,
default_ms
):
def
test_get_modulestore_type
(
self
,
default_ms
):
"""
"""
Make sure we get back the store type we expect for given mappings
Make sure we get back the store type we expect for given mappings
...
@@ -310,16 +313,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -310,16 +313,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
self
.
_course_key_from_string
(
self
.
XML_COURSEID2
)),
ModuleStoreEnum
.
Type
.
xml
self
.
_course_key_from_string
(
self
.
XML_COURSEID2
)),
ModuleStoreEnum
.
Type
.
xml
)
)
mongo_ms_type
=
ModuleStoreEnum
.
Type
.
mongo
if
default_ms
==
'draft'
else
ModuleStoreEnum
.
Type
.
split
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
self
.
_course_key_from_string
(
self
.
MONGO_COURSEID
)),
mongo_ms_type
self
.
_course_key_from_string
(
self
.
MONGO_COURSEID
)),
default_ms
)
)
# try an unknown mapping, it should be the 'default' store
# try an unknown mapping, it should be the 'default' store
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
self
.
assertEqual
(
self
.
store
.
get_modulestore_type
(
SlashSeparatedCourseKey
(
'foo'
,
'bar'
,
'2012_Fall'
)),
mongo_ms_type
SlashSeparatedCourseKey
(
'foo'
,
'bar'
,
'2012_Fall'
)),
default_ms
)
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_get_modulestore_cache
(
self
,
default_ms
):
def
test_get_modulestore_cache
(
self
,
default_ms
):
"""
"""
Make sure we cache discovered course mappings
Make sure we cache discovered course mappings
...
@@ -354,7 +356,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -354,7 +356,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# problem: One lookup to locate an item that exists
# problem: One lookup to locate an item that exists
# fake: one w/ wildcard version
# fake: one w/ wildcard version
# split has one lookup for the course and then one for the course items
# split has one lookup for the course and then one for the course items
@ddt.data
((
'draft'
,
[
1
,
1
],
0
),
(
'split'
,
[
2
,
2
],
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
[
1
,
1
],
0
),
(
ModuleStoreEnum
.
Type
.
split
,
[
2
,
2
],
0
))
@ddt.unpack
@ddt.unpack
def
test_has_item
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_has_item
(
self
,
default_ms
,
max_find
,
max_send
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
...
@@ -382,7 +384,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -382,7 +384,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# split:
# split:
# problem: active_versions, structure
# problem: active_versions, structure
# non-existent problem: ditto
# non-existent problem: ditto
@ddt.data
((
'draft'
,
[
3
,
2
],
0
),
(
'split'
,
[
2
,
2
],
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
[
3
,
2
],
0
),
(
ModuleStoreEnum
.
Type
.
split
,
[
2
,
2
],
0
))
@ddt.unpack
@ddt.unpack
def
test_get_item
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_item
(
self
,
default_ms
,
max_find
,
max_send
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
...
@@ -410,7 +412,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -410,7 +412,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# wildcard query, 6! load pertinent items for inheritance calls, load parents, course root fetch (why)
# wildcard query, 6! load pertinent items for inheritance calls, load parents, course root fetch (why)
# Split:
# Split:
# active_versions (with regex), structure, and spurious active_versions refetch
# active_versions (with regex), structure, and spurious active_versions refetch
@ddt.data
((
'draft'
,
14
,
0
),
(
'split'
,
3
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
14
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_items
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_items
(
self
,
default_ms
,
max_find
,
max_send
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
...
@@ -438,7 +440,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -438,7 +440,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# sends: update problem and then each ancestor up to course (edit info)
# sends: update problem and then each ancestor up to course (edit info)
# split: active_versions, definitions (calculator field), structures
# split: active_versions, definitions (calculator field), structures
# 2 sends to update index & structure (note, it would also be definition if a content field changed)
# 2 sends to update index & structure (note, it would also be definition if a content field changed)
@ddt.data
((
'draft'
,
7
,
5
),
(
'split'
,
3
,
2
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
7
,
5
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
2
))
@ddt.unpack
@ddt.unpack
def
test_update_item
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_update_item
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -463,7 +465,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -463,7 +465,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertEqual
(
problem
.
max_attempts
,
2
,
"Update didn't persist"
)
self
.
assertEqual
(
problem
.
max_attempts
,
2
,
"Update didn't persist"
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes_direct_only
(
self
,
default_ms
):
def
test_has_changes_direct_only
(
self
,
default_ms
):
"""
"""
Tests that has_changes() returns false when a new xblock in a direct only category is checked
Tests that has_changes() returns false when a new xblock in a direct only category is checked
...
@@ -484,7 +486,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -484,7 +486,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertFalse
(
self
.
store
.
has_changes
(
test_course
))
self
.
assertFalse
(
self
.
store
.
has_changes
(
test_course
))
self
.
assertFalse
(
self
.
store
.
has_changes
(
chapter
))
self
.
assertFalse
(
self
.
store
.
has_changes
(
chapter
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes
(
self
,
default_ms
):
def
test_has_changes
(
self
,
default_ms
):
"""
"""
Tests that has_changes() only returns true when changes are present
Tests that has_changes() only returns true when changes are present
...
@@ -519,7 +521,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -519,7 +521,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
component
=
self
.
store
.
publish
(
component
.
location
,
self
.
user_id
)
component
=
self
.
store
.
publish
(
component
.
location
,
self
.
user_id
)
self
.
assertFalse
(
self
.
store
.
has_changes
(
component
))
self
.
assertFalse
(
self
.
store
.
has_changes
(
component
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_unit_stuck_in_draft_mode
(
self
,
default_ms
):
def
test_unit_stuck_in_draft_mode
(
self
,
default_ms
):
"""
"""
After revert_to_published() the has_changes() should return false if draft has no changes
After revert_to_published() the has_changes() should return false if draft has no changes
...
@@ -551,7 +553,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -551,7 +553,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
component
=
self
.
store
.
publish
(
component
.
location
,
self
.
user_id
)
component
=
self
.
store
.
publish
(
component
.
location
,
self
.
user_id
)
self
.
assertFalse
(
self
.
store
.
has_changes
(
component
))
self
.
assertFalse
(
self
.
store
.
has_changes
(
component
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_unit_stuck_in_published_mode
(
self
,
default_ms
):
def
test_unit_stuck_in_published_mode
(
self
,
default_ms
):
"""
"""
After revert_to_published() the has_changes() should return true if draft has changes
After revert_to_published() the has_changes() should return true if draft has changes
...
@@ -588,7 +590,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -588,7 +590,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Verify that changes are present
# Verify that changes are present
self
.
assertTrue
(
self
.
store
.
has_changes
(
component
))
self
.
assertTrue
(
self
.
store
.
has_changes
(
component
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_unit_stuck_in_published_mode_after_delete
(
self
,
default_ms
):
def
test_unit_stuck_in_published_mode_after_delete
(
self
,
default_ms
):
"""
"""
Test that a unit does not get stuck in published mode
Test that a unit does not get stuck in published mode
...
@@ -631,7 +633,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -631,7 +633,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
vertical
=
self
.
store
.
get_item
(
vertical
.
location
)
vertical
=
self
.
store
.
get_item
(
vertical
.
location
)
self
.
assertTrue
(
self
.
_has_changes
(
vertical
.
location
))
self
.
assertTrue
(
self
.
_has_changes
(
vertical
.
location
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_publish_automatically_after_delete_unit
(
self
,
default_ms
):
def
test_publish_automatically_after_delete_unit
(
self
,
default_ms
):
"""
"""
Check that sequential publishes automatically after deleting a unit
Check that sequential publishes automatically after deleting a unit
...
@@ -674,7 +676,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -674,7 +676,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
return
locations
return
locations
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes_ancestors
(
self
,
default_ms
):
def
test_has_changes_ancestors
(
self
,
default_ms
):
"""
"""
Tests that has_changes() returns true on ancestors when a child is changed
Tests that has_changes() returns true on ancestors when a child is changed
...
@@ -704,7 +706,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -704,7 +706,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
for
key
in
locations
:
for
key
in
locations
:
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
key
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
key
]))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes_publish_ancestors
(
self
,
default_ms
):
def
test_has_changes_publish_ancestors
(
self
,
default_ms
):
"""
"""
Tests that has_changes() returns false after a child is published only if all children are unchanged
Tests that has_changes() returns false after a child is published only if all children are unchanged
...
@@ -741,7 +743,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -741,7 +743,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'grandparent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'grandparent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'parent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'parent'
]))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes_add_remove_child
(
self
,
default_ms
):
def
test_has_changes_add_remove_child
(
self
,
default_ms
):
"""
"""
Tests that has_changes() returns true for the parent when a child with changes is added
Tests that has_changes() returns true for the parent when a child with changes is added
...
@@ -774,7 +776,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -774,7 +776,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'grandparent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'grandparent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'parent'
]))
self
.
assertFalse
(
self
.
_has_changes
(
locations
[
'parent'
]))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_has_changes_non_direct_only_children
(
self
,
default_ms
):
def
test_has_changes_non_direct_only_children
(
self
,
default_ms
):
"""
"""
Tests that has_changes() returns true after editing the child of a vertical (both not direct only categories).
Tests that has_changes() returns true after editing the child of a vertical (both not direct only categories).
...
@@ -808,7 +810,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -808,7 +810,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertTrue
(
self
.
_has_changes
(
child
.
location
))
self
.
assertTrue
(
self
.
_has_changes
(
child
.
location
))
@ddt.data
(
*
itertools
.
product
(
@ddt.data
(
*
itertools
.
product
(
(
'draft'
,
'split'
),
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
),
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
ModuleStoreEnum
.
Branch
.
published_only
)
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
ModuleStoreEnum
.
Branch
.
published_only
)
))
))
@ddt.unpack
@ddt.unpack
...
@@ -840,14 +842,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -840,14 +842,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Split
# Split
# Find: active_versions, 2 structures (published & draft), definition (unnecessary)
# Find: active_versions, 2 structures (published & draft), definition (unnecessary)
# Sends: updated draft and published structures and active_versions
# Sends: updated draft and published structures and active_versions
@ddt.data
((
'draft'
,
7
,
2
),
(
'split'
,
4
,
3
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
7
,
2
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
3
))
@ddt.unpack
@ddt.unpack
def
test_delete_item
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_delete_item
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
Delete should reject on r/o db and work on r/w one
Delete should reject on r/o db and work on r/w one
"""
"""
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
if
default_ms
==
'draft'
and
mongo_uses_error_check
(
self
.
store
):
if
default_ms
==
ModuleStoreEnum
.
Type
.
mongo
and
mongo_uses_error_check
(
self
.
store
):
max_find
+=
1
max_find
+=
1
# r/o try deleting the chapter (is here to ensure it can't be deleted)
# r/o try deleting the chapter (is here to ensure it can't be deleted)
...
@@ -872,7 +874,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -872,7 +874,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Split:
# Split:
# queries: active_versions, draft and published structures, definition (unnecessary)
# queries: active_versions, draft and published structures, definition (unnecessary)
# sends: update published (why?), draft, and active_versions
# sends: update published (why?), draft, and active_versions
@ddt.data
((
'draft'
,
9
,
2
),
(
'split'
,
4
,
3
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
9
,
2
),
(
ModuleStoreEnum
.
Type
.
split
,
4
,
3
))
@ddt.unpack
@ddt.unpack
def
test_delete_private_vertical
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_delete_private_vertical
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -880,7 +882,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -880,7 +882,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
behavioral properties which this deletion test gets at.
behavioral properties which this deletion test gets at.
"""
"""
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
if
default_ms
==
'draft'
and
mongo_uses_error_check
(
self
.
store
):
if
default_ms
==
ModuleStoreEnum
.
Type
.
mongo
and
mongo_uses_error_check
(
self
.
store
):
max_find
+=
1
max_find
+=
1
# create and delete a private vertical with private children
# create and delete a private vertical with private children
private_vert
=
self
.
store
.
create_child
(
private_vert
=
self
.
store
.
create_child
(
...
@@ -925,7 +927,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -925,7 +927,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Split:
# Split:
# find: active_version & structure (cached)
# find: active_version & structure (cached)
# send: update structure and active_versions
# send: update structure and active_versions
@ddt.data
((
'draft'
,
4
,
1
),
(
'split'
,
2
,
2
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
4
,
1
),
(
ModuleStoreEnum
.
Type
.
split
,
2
,
2
))
@ddt.unpack
@ddt.unpack
def
test_delete_draft_vertical
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_delete_draft_vertical
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -955,7 +957,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -955,7 +957,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
private_leaf
.
display_name
=
'change me'
private_leaf
.
display_name
=
'change me'
private_leaf
=
self
.
store
.
update_item
(
private_leaf
,
self
.
user_id
)
private_leaf
=
self
.
store
.
update_item
(
private_leaf
,
self
.
user_id
)
# test succeeds if delete succeeds w/o error
# test succeeds if delete succeeds w/o error
if
default_ms
==
'draft'
and
mongo_uses_error_check
(
self
.
store
):
if
default_ms
==
ModuleStoreEnum
.
Type
.
mongo
and
mongo_uses_error_check
(
self
.
store
):
max_find
+=
1
max_find
+=
1
with
check_mongo_calls
(
max_find
,
max_send
):
with
check_mongo_calls
(
max_find
,
max_send
):
self
.
store
.
delete_item
(
private_leaf
.
location
,
self
.
user_id
)
self
.
store
.
delete_item
(
private_leaf
.
location
,
self
.
user_id
)
...
@@ -968,7 +970,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -968,7 +970,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# 1) wildcard split search,
# 1) wildcard split search,
# 2-4) active_versions, structure, definition (s/b lazy; so, unnecessary)
# 2-4) active_versions, structure, definition (s/b lazy; so, unnecessary)
# 5) wildcard draft mongo which has none
# 5) wildcard draft mongo which has none
@ddt.data
((
'draft'
,
3
,
0
),
(
'split'
,
5
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
3
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
5
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_courses
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_courses
(
self
,
default_ms
,
max_find
,
max_send
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
...
@@ -987,7 +989,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -987,7 +989,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
published_courses
=
self
.
store
.
get_courses
(
remove_branch
=
True
)
published_courses
=
self
.
store
.
get_courses
(
remove_branch
=
True
)
self
.
assertEquals
([
c
.
id
for
c
in
draft_courses
],
[
c
.
id
for
c
in
published_courses
])
self
.
assertEquals
([
c
.
id
for
c
in
draft_courses
],
[
c
.
id
for
c
in
published_courses
])
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_create_child_detached_tabs
(
self
,
default_ms
):
def
test_create_child_detached_tabs
(
self
,
default_ms
):
"""
"""
test 'create_child' method with a detached category ('static_tab')
test 'create_child' method with a detached category ('static_tab')
...
@@ -1012,7 +1014,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1012,7 +1014,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
"""
"""
Test that the xml modulestore only loaded the courses from the maps.
Test that the xml modulestore only loaded the courses from the maps.
"""
"""
self
.
initdb
(
'draft'
)
self
.
initdb
(
ModuleStoreEnum
.
Type
.
mongo
)
xml_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
xml
)
# pylint: disable=protected-access
xml_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
xml
)
# pylint: disable=protected-access
courses
=
xml_store
.
get_courses
()
courses
=
xml_store
.
get_courses
()
self
.
assertEqual
(
len
(
courses
),
2
)
self
.
assertEqual
(
len
(
courses
),
2
)
...
@@ -1026,7 +1028,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1026,7 +1028,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
"""
"""
Test that the xml modulestore doesn't allow write ops.
Test that the xml modulestore doesn't allow write ops.
"""
"""
self
.
initdb
(
'draft'
)
self
.
initdb
(
ModuleStoreEnum
.
Type
.
mongo
)
xml_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
xml
)
# pylint: disable=protected-access
xml_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
xml
)
# pylint: disable=protected-access
# the important thing is not which exception it raises but that it raises an exception
# the important thing is not which exception it raises but that it raises an exception
with
self
.
assertRaises
(
AttributeError
):
with
self
.
assertRaises
(
AttributeError
):
...
@@ -1034,7 +1036,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1034,7 +1036,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# draft is 2: find out which ms owns course, get item
# draft is 2: find out which ms owns course, get item
# split: active_versions, structure, definition (to load course wiki string)
# split: active_versions, structure, definition (to load course wiki string)
@ddt.data
((
'draft'
,
2
,
0
),
(
'split'
,
3
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
2
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_course
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_course
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -1049,7 +1051,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1049,7 +1051,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
course
=
self
.
store
.
get_item
(
self
.
course_locations
[
self
.
XML_COURSEID1
])
course
=
self
.
store
.
get_item
(
self
.
course_locations
[
self
.
XML_COURSEID1
])
self
.
assertEqual
(
course
.
id
,
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
course_key
)
self
.
assertEqual
(
course
.
id
,
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
course_key
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_get_library
(
self
,
default_ms
):
def
test_get_library
(
self
,
default_ms
):
"""
"""
Test that create_library and get_library work regardless of the default modulestore.
Test that create_library and get_library work regardless of the default modulestore.
...
@@ -1074,7 +1076,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1074,7 +1076,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# still only 2)
# still only 2)
# Draft: get_parent
# Draft: get_parent
# Split: active_versions, structure
# Split: active_versions, structure
@ddt.data
((
'draft'
,
1
,
0
),
(
'split'
,
2
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
1
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
2
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_parent_locations
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_parent_locations
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -1100,7 +1102,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1100,7 +1102,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
store
.
get_parent_location
(
child_location
,
revision
=
revision
)
self
.
store
.
get_parent_location
(
child_location
,
revision
=
revision
)
)
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_get_parent_locations_moved_child
(
self
,
default_ms
):
def
test_get_parent_locations_moved_child
(
self
,
default_ms
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
self
.
_create_block_hierarchy
()
self
.
_create_block_hierarchy
()
...
@@ -1151,7 +1153,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1151,7 +1153,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
(
child_to_move_location
,
new_parent_published_location
,
ModuleStoreEnum
.
RevisionOption
.
published_only
),
(
child_to_move_location
,
new_parent_published_location
,
ModuleStoreEnum
.
RevisionOption
.
published_only
),
])
])
@ddt.data
(
'draft'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
)
def
test_get_parent_locations_deleted_child
(
self
,
default_ms
):
def
test_get_parent_locations_deleted_child
(
self
,
default_ms
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
self
.
_create_block_hierarchy
()
self
.
_create_block_hierarchy
()
...
@@ -1182,7 +1184,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1182,7 +1184,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
(
child_to_delete_location
,
None
,
ModuleStoreEnum
.
RevisionOption
.
published_only
),
(
child_to_delete_location
,
None
,
ModuleStoreEnum
.
RevisionOption
.
published_only
),
])
])
@ddt.data
(
'draft'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
)
def
test_get_parent_location_draft
(
self
,
default_ms
):
def
test_get_parent_location_draft
(
self
,
default_ms
):
"""
"""
Test that "get_parent_location" method returns first published parent
Test that "get_parent_location" method returns first published parent
...
@@ -1225,7 +1227,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1225,7 +1227,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# 8-9. get vertical, compute inheritance
# 8-9. get vertical, compute inheritance
# 10-11. get other vertical_x1b (why?) and compute inheritance
# 10-11. get other vertical_x1b (why?) and compute inheritance
# Split: active_versions & structure
# Split: active_versions & structure
@ddt.data
((
'draft'
,
[
12
,
3
],
0
),
(
'split'
,
[
2
,
2
],
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
[
12
,
3
],
0
),
(
ModuleStoreEnum
.
Type
.
split
,
[
2
,
2
],
0
))
@ddt.unpack
@ddt.unpack
def
test_path_to_location
(
self
,
default_ms
,
num_finds
,
num_sends
):
def
test_path_to_location
(
self
,
default_ms
,
num_finds
,
num_sends
):
"""
"""
...
@@ -1276,7 +1278,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1276,7 +1278,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
with the toy and simple courses loaded.
with the toy and simple courses loaded.
"""
"""
# only needs course_locations set
# only needs course_locations set
self
.
initdb
(
'draft'
)
self
.
initdb
(
ModuleStoreEnum
.
Type
.
mongo
)
course_key
=
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
course_key
course_key
=
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
course_key
video_key
=
course_key
.
make_usage_key
(
'video'
,
'Welcome'
)
video_key
=
course_key
.
make_usage_key
(
'video'
,
'Welcome'
)
chapter_key
=
course_key
.
make_usage_key
(
'chapter'
,
'Overview'
)
chapter_key
=
course_key
.
make_usage_key
(
'chapter'
,
'Overview'
)
...
@@ -1310,7 +1312,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1310,7 +1312,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertEqual
(
5
,
navigation_index
(
"5_2"
))
self
.
assertEqual
(
5
,
navigation_index
(
"5_2"
))
self
.
assertEqual
(
7
,
navigation_index
(
"7_3_5_6_"
))
self
.
assertEqual
(
7
,
navigation_index
(
"7_3_5_6_"
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_revert_to_published_root_draft
(
self
,
default_ms
):
def
test_revert_to_published_root_draft
(
self
,
default_ms
):
"""
"""
Test calling revert_to_published on draft vertical.
Test calling revert_to_published on draft vertical.
...
@@ -1342,7 +1344,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1342,7 +1344,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertBlocksEqualByFields
(
reverted_parent
,
published_parent
)
self
.
assertBlocksEqualByFields
(
reverted_parent
,
published_parent
)
self
.
assertFalse
(
self
.
_has_changes
(
self
.
vertical_x1a
))
self
.
assertFalse
(
self
.
_has_changes
(
self
.
vertical_x1a
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_revert_to_published_root_published
(
self
,
default_ms
):
def
test_revert_to_published_root_published
(
self
,
default_ms
):
"""
"""
Test calling revert_to_published on a published vertical with a draft child.
Test calling revert_to_published on a published vertical with a draft child.
...
@@ -1362,7 +1364,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1362,7 +1364,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
reverted_problem
=
self
.
store
.
get_item
(
self
.
problem_x1a_1
)
reverted_problem
=
self
.
store
.
get_item
(
self
.
problem_x1a_1
)
self
.
assertEqual
(
orig_display_name
,
reverted_problem
.
display_name
)
self
.
assertEqual
(
orig_display_name
,
reverted_problem
.
display_name
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_revert_to_published_no_draft
(
self
,
default_ms
):
def
test_revert_to_published_no_draft
(
self
,
default_ms
):
"""
"""
Test calling revert_to_published on vertical with no draft content does nothing.
Test calling revert_to_published on vertical with no draft content does nothing.
...
@@ -1377,7 +1379,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1377,7 +1379,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertBlocksEqualByFields
(
orig_vertical
,
reverted_vertical
)
self
.
assertBlocksEqualByFields
(
orig_vertical
,
reverted_vertical
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_revert_to_published_no_published
(
self
,
default_ms
):
def
test_revert_to_published_no_published
(
self
,
default_ms
):
"""
"""
Test calling revert_to_published on vertical with no published version errors.
Test calling revert_to_published on vertical with no published version errors.
...
@@ -1387,7 +1389,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1387,7 +1389,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
with
self
.
assertRaises
(
InvalidVersionError
):
with
self
.
assertRaises
(
InvalidVersionError
):
self
.
store
.
revert_to_published
(
self
.
vertical_x1a
,
self
.
user_id
)
self
.
store
.
revert_to_published
(
self
.
vertical_x1a
,
self
.
user_id
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_revert_to_published_direct_only
(
self
,
default_ms
):
def
test_revert_to_published_direct_only
(
self
,
default_ms
):
"""
"""
Test calling revert_to_published on a direct-only item is a no-op.
Test calling revert_to_published on a direct-only item is a no-op.
...
@@ -1402,7 +1404,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1402,7 +1404,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Draft: get all items which can be or should have parents
# Draft: get all items which can be or should have parents
# Split: active_versions, structure
# Split: active_versions, structure
@ddt.data
((
'draft'
,
1
,
0
),
(
'split'
,
2
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
1
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
2
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_orphans
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_orphans
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -1440,7 +1442,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1440,7 +1442,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
found_orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
found_orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
assertItemsEqual
(
found_orphans
,
orphan_locations
)
self
.
assertItemsEqual
(
found_orphans
,
orphan_locations
)
@ddt.data
(
'draft'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
)
def
test_get_non_orphan_parents
(
self
,
default_ms
):
def
test_get_non_orphan_parents
(
self
,
default_ms
):
"""
"""
Test finding non orphan parents from many possible parents.
Test finding non orphan parents from many possible parents.
...
@@ -1502,7 +1504,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1502,7 +1504,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
with
self
.
assertRaises
(
ReferentialIntegrityError
):
with
self
.
assertRaises
(
ReferentialIntegrityError
):
self
.
store
.
get_parent_location
(
self
.
problem_x1a_1
)
self
.
store
.
get_parent_location
(
self
.
problem_x1a_1
)
@ddt.data
(
'draft'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
)
def
test_create_item_from_parent_location
(
self
,
default_ms
):
def
test_create_item_from_parent_location
(
self
,
default_ms
):
"""
"""
Test a code path missed by the above: passing an old-style location as parent but no
Test a code path missed by the above: passing an old-style location as parent but no
...
@@ -1518,7 +1520,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1518,7 +1520,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
assertEqual
(
len
(
orphans
),
0
,
"unexpected orphans: {}"
.
format
(
orphans
))
self
.
assertEqual
(
len
(
orphans
),
0
,
"unexpected orphans: {}"
.
format
(
orphans
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_create_item_populates_edited_info
(
self
,
default_ms
):
def
test_create_item_populates_edited_info
(
self
,
default_ms
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
block
=
self
.
store
.
create_item
(
block
=
self
.
store
.
create_item
(
...
@@ -1529,7 +1531,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1529,7 +1531,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertEqual
(
self
.
user_id
,
block
.
edited_by
)
self
.
assertEqual
(
self
.
user_id
,
block
.
edited_by
)
self
.
assertGreater
(
datetime
.
datetime
.
now
(
UTC
),
block
.
edited_on
)
self
.
assertGreater
(
datetime
.
datetime
.
now
(
UTC
),
block
.
edited_on
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_create_item_populates_subtree_edited_info
(
self
,
default_ms
):
def
test_create_item_populates_subtree_edited_info
(
self
,
default_ms
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
block
=
self
.
store
.
create_item
(
block
=
self
.
store
.
create_item
(
...
@@ -1542,7 +1544,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1542,7 +1544,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Draft: wildcard search of draft and split
# Draft: wildcard search of draft and split
# Split: wildcard search of draft and split
# Split: wildcard search of draft and split
@ddt.data
((
'draft'
,
2
,
0
),
(
'split'
,
2
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
2
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
2
,
0
))
@ddt.unpack
@ddt.unpack
def
test_get_courses_for_wiki
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_get_courses_for_wiki
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -1580,14 +1582,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1580,14 +1582,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Sends:
# Sends:
# - insert structure
# - insert structure
# - write index entry
# - write index entry
@ddt.data
((
'draft'
,
2
,
6
),
(
'split'
,
3
,
2
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
2
,
6
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
2
))
@ddt.unpack
@ddt.unpack
def
test_unpublish
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_unpublish
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
Test calling unpublish
Test calling unpublish
"""
"""
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
if
default_ms
==
'draft'
and
mongo_uses_error_check
(
self
.
store
):
if
default_ms
==
ModuleStoreEnum
.
Type
.
mongo
and
mongo_uses_error_check
(
self
.
store
):
max_find
+=
1
max_find
+=
1
self
.
_create_block_hierarchy
()
self
.
_create_block_hierarchy
()
...
@@ -1618,7 +1620,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1618,7 +1620,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Draft: specific query for revision None
# Draft: specific query for revision None
# Split: active_versions, structure
# Split: active_versions, structure
@ddt.data
((
'draft'
,
1
,
0
),
(
'split'
,
2
,
0
))
@ddt.data
((
ModuleStoreEnum
.
Type
.
mongo
,
1
,
0
),
(
ModuleStoreEnum
.
Type
.
split
,
2
,
0
))
@ddt.unpack
@ddt.unpack
def
test_has_published_version
(
self
,
default_ms
,
max_find
,
max_send
):
def
test_has_published_version
(
self
,
default_ms
,
max_find
,
max_send
):
"""
"""
...
@@ -1659,7 +1661,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1659,7 +1661,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertTrue
(
self
.
store
.
has_changes
(
item
))
self
.
assertTrue
(
self
.
store
.
has_changes
(
item
))
self
.
assertTrue
(
self
.
store
.
has_published_version
(
item
))
self
.
assertTrue
(
self
.
store
.
has_published_version
(
item
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_update_edit_info_ancestors
(
self
,
default_ms
):
def
test_update_edit_info_ancestors
(
self
,
default_ms
):
"""
"""
Tests that edited_on, edited_by, subtree_edited_on, and subtree_edited_by are set correctly during update
Tests that edited_on, edited_by, subtree_edited_on, and subtree_edited_by are set correctly during update
...
@@ -1735,7 +1737,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1735,7 +1737,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Verify that others have unchanged edit info
# Verify that others have unchanged edit info
check_node
(
sibling
.
location
,
None
,
after_create
,
self
.
user_id
,
None
,
after_create
,
self
.
user_id
)
check_node
(
sibling
.
location
,
None
,
after_create
,
self
.
user_id
,
None
,
after_create
,
self
.
user_id
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_update_edit_info
(
self
,
default_ms
):
def
test_update_edit_info
(
self
,
default_ms
):
"""
"""
Tests that edited_on and edited_by are set correctly during an update
Tests that edited_on and edited_by are set correctly during an update
...
@@ -1765,7 +1767,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1765,7 +1767,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertLess
(
old_edited_on
,
updated_component
.
edited_on
)
self
.
assertLess
(
old_edited_on
,
updated_component
.
edited_on
)
self
.
assertEqual
(
updated_component
.
edited_by
,
edit_user
)
self
.
assertEqual
(
updated_component
.
edited_by
,
edit_user
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_update_published_info
(
self
,
default_ms
):
def
test_update_published_info
(
self
,
default_ms
):
"""
"""
Tests that published_on and published_by are set correctly
Tests that published_on and published_by are set correctly
...
@@ -1799,7 +1801,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1799,7 +1801,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self
.
assertLessEqual
(
old_time
,
updated_component
.
published_on
)
self
.
assertLessEqual
(
old_time
,
updated_component
.
published_on
)
self
.
assertEqual
(
updated_component
.
published_by
,
publish_user
)
self
.
assertEqual
(
updated_component
.
published_by
,
publish_user
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_auto_publish
(
self
,
default_ms
):
def
test_auto_publish
(
self
,
default_ms
):
"""
"""
Test that the correct things have been published automatically
Test that the correct things have been published automatically
...
@@ -1869,7 +1871,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1869,7 +1871,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
chapter
=
self
.
store
.
get_item
(
chapter
.
location
.
for_branch
(
None
))
chapter
=
self
.
store
.
get_item
(
chapter
.
location
.
for_branch
(
None
))
self
.
assertTrue
(
self
.
store
.
has_published_version
(
chapter
))
self
.
assertTrue
(
self
.
store
.
has_published_version
(
chapter
))
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_get_courses_for_wiki_shared
(
self
,
default_ms
):
def
test_get_courses_for_wiki_shared
(
self
,
default_ms
):
"""
"""
Test two courses sharing the same wiki
Test two courses sharing the same wiki
...
@@ -1924,7 +1926,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -1924,7 +1926,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
wiki_courses
wiki_courses
)
)
@ddt.data
(
'draft'
,
'split'
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_branch_setting
(
self
,
default_ms
):
def
test_branch_setting
(
self
,
default_ms
):
"""
"""
Test the branch_setting context manager
Test the branch_setting context manager
...
@@ -2473,6 +2475,119 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
...
@@ -2473,6 +2475,119 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
# Verify that the signal was emitted
# Verify that the signal was emitted
signal_handler
.
send
.
assert_called_with
(
'course_deleted'
,
course_key
=
course_key
)
signal_handler
.
send
.
assert_called_with
(
'course_deleted'
,
course_key
=
course_key
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_delete_published_item_orphans
(
self
,
default_store
):
"""
Tests delete published item dont create any oprhans in course
"""
self
.
initdb
(
default_store
)
course_locator
=
self
.
course
.
id
chapter
=
self
.
store
.
create_child
(
self
.
user_id
,
self
.
course
.
location
,
'chapter'
,
block_id
=
'section_one'
)
sequential
=
self
.
store
.
create_child
(
self
.
user_id
,
chapter
.
location
,
'sequential'
,
block_id
=
'subsection_one'
)
vertical
=
self
.
store
.
create_child
(
self
.
user_id
,
sequential
.
location
,
'vertical'
,
block_id
=
'moon_unit'
)
problem
=
self
.
store
.
create_child
(
self
.
user_id
,
vertical
.
location
,
'problem'
,
block_id
=
'problem'
)
self
.
store
.
publish
(
chapter
.
location
,
self
.
user_id
)
# Verify that there are no changes
self
.
assertFalse
(
self
.
_has_changes
(
chapter
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
sequential
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
vertical
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
problem
.
location
))
# No orphans in course
course_orphans
=
self
.
store
.
get_orphans
(
course_locator
)
self
.
assertEqual
(
len
(
course_orphans
),
0
)
self
.
store
.
delete_item
(
vertical
.
location
,
self
.
user_id
)
# No orphans in course after delete, except
# in old mongo, which still creates orphans
course_orphans
=
self
.
store
.
get_orphans
(
course_locator
)
if
default_store
==
ModuleStoreEnum
.
Type
.
mongo
:
self
.
assertEqual
(
len
(
course_orphans
),
1
)
else
:
self
.
assertEqual
(
len
(
course_orphans
),
0
)
course_locator_publish
=
course_locator
.
for_branch
(
ModuleStoreEnum
.
BranchName
.
published
)
# No published oprhans after delete, except
# in old mongo, which still creates orphans
course_publish_orphans
=
self
.
store
.
get_orphans
(
course_locator_publish
)
if
default_store
==
ModuleStoreEnum
.
Type
.
mongo
:
self
.
assertEqual
(
len
(
course_publish_orphans
),
1
)
else
:
self
.
assertEqual
(
len
(
course_publish_orphans
),
0
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_delete_draft_item_orphans
(
self
,
default_store
):
"""
Tests delete draft item create no orphans in course
"""
self
.
initdb
(
default_store
)
course_locator
=
self
.
course
.
id
chapter
=
self
.
store
.
create_child
(
self
.
user_id
,
self
.
course
.
location
,
'chapter'
,
block_id
=
'section_one'
)
sequential
=
self
.
store
.
create_child
(
self
.
user_id
,
chapter
.
location
,
'sequential'
,
block_id
=
'subsection_one'
)
vertical
=
self
.
store
.
create_child
(
self
.
user_id
,
sequential
.
location
,
'vertical'
,
block_id
=
'moon_unit'
)
problem
=
self
.
store
.
create_child
(
self
.
user_id
,
vertical
.
location
,
'problem'
,
block_id
=
'problem'
)
self
.
store
.
publish
(
chapter
.
location
,
self
.
user_id
)
# Verify that there are no changes
self
.
assertFalse
(
self
.
_has_changes
(
chapter
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
sequential
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
vertical
.
location
))
self
.
assertFalse
(
self
.
_has_changes
(
problem
.
location
))
# No orphans in course
course_orphans
=
self
.
store
.
get_orphans
(
course_locator
)
self
.
assertEqual
(
len
(
course_orphans
),
0
)
problem
.
display_name
=
'changed'
problem
=
self
.
store
.
update_item
(
problem
,
self
.
user_id
)
self
.
assertTrue
(
self
.
_has_changes
(
vertical
.
location
))
self
.
assertTrue
(
self
.
_has_changes
(
problem
.
location
))
self
.
store
.
delete_item
(
vertical
.
location
,
self
.
user_id
)
# No orphans in course after delete, except
# in old mongo, which still creates them
course_orphans
=
self
.
store
.
get_orphans
(
course_locator
)
if
default_store
==
ModuleStoreEnum
.
Type
.
mongo
:
self
.
assertEqual
(
len
(
course_orphans
),
1
)
else
:
self
.
assertEqual
(
len
(
course_orphans
),
0
)
course_locator_publish
=
course_locator
.
for_branch
(
ModuleStoreEnum
.
BranchName
.
published
)
# No published orphans after delete, except
# in old mongo, which still creates them
course_publish_orphans
=
self
.
store
.
get_orphans
(
course_locator_publish
)
if
default_store
==
ModuleStoreEnum
.
Type
.
mongo
:
self
.
assertEqual
(
len
(
course_publish_orphans
),
1
)
else
:
self
.
assertEqual
(
len
(
course_publish_orphans
),
0
)
@ddt.ddt
@ddt.ddt
@attr
(
'mongo'
)
@attr
(
'mongo'
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_publish.py
View file @
e65730b9
...
@@ -1122,20 +1122,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
...
@@ -1122,20 +1122,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
self
.
assertOLXIsPublishedOnly
(
block_list_to_delete
)
self
.
assertOLXIsPublishedOnly
(
block_list_to_delete
)
self
.
delete_item
(
block_list_to_delete
,
revision
=
revision
)
self
.
delete_item
(
block_list_to_delete
,
revision
=
revision
)
self
.
_check_for_item_deletion
(
block_list_to_delete
,
result
)
self
.
_check_for_item_deletion
(
block_list_to_delete
,
result
)
# MODULESTORE_DIFFERENCE
if
self
.
is_split_modulestore
:
# Split:
if
revision
==
ModuleStoreEnum
.
RevisionOption
.
published_only
:
# If deleting published_only items, the children that are drafts remain.
self
.
assertOLXIsDraftOnly
(
block_list_children
)
else
:
self
.
assertOLXIsDeleted
(
block_list_children
)
self
.
assertOLXIsDeleted
(
block_list_children
)
elif
self
.
is_old_mongo_modulestore
:
# Old Mongo:
# If deleting draft_only or both items, the drafts will be deleted.
self
.
assertOLXIsDeleted
(
block_list_children
)
else
:
raise
Exception
(
"Must test either Old Mongo or Split modulestore!"
)
@ddt.data
(
*
itertools
.
product
(
@ddt.data
(
*
itertools
.
product
(
MODULESTORE_SETUPS
,
MODULESTORE_SETUPS
,
...
@@ -1176,20 +1163,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
...
@@ -1176,20 +1163,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
self
.
delete_item
(
block_list_to_delete
,
revision
=
revision
)
self
.
delete_item
(
block_list_to_delete
,
revision
=
revision
)
self
.
_check_for_item_deletion
(
block_list_to_delete
,
result
)
self
.
_check_for_item_deletion
(
block_list_to_delete
,
result
)
self
.
assertOLXIsDeleted
(
autopublished_children
)
self
.
assertOLXIsDeleted
(
autopublished_children
)
# MODULESTORE_DIFFERENCE
if
self
.
is_split_modulestore
:
# Split:
if
revision
==
ModuleStoreEnum
.
RevisionOption
.
published_only
:
# If deleting published_only items, the children that are drafts remain.
self
.
assertOLXIsDraftOnly
(
block_list_draft_children
)
else
:
self
.
assertOLXIsDeleted
(
block_list_draft_children
)
elif
self
.
is_old_mongo_modulestore
:
# Old Mongo:
# If deleting draft_only or both items, the drafts will be deleted.
self
.
assertOLXIsDeleted
(
block_list_draft_children
)
self
.
assertOLXIsDeleted
(
block_list_draft_children
)
else
:
raise
Exception
(
"Must test either Old Mongo or Split modulestore!"
)
@ddt.ddt
@ddt.ddt
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py
View file @
e65730b9
...
@@ -3,6 +3,7 @@ Tests of modulestore semantics: How do the interfaces methods of ModuleStore rel
...
@@ -3,6 +3,7 @@ Tests of modulestore semantics: How do the interfaces methods of ModuleStore rel
"""
"""
import
ddt
import
ddt
import
itertools
from
collections
import
namedtuple
from
collections
import
namedtuple
from
xmodule.modulestore.tests.utils
import
(
from
xmodule.modulestore.tests.utils
import
(
...
@@ -51,45 +52,130 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
...
@@ -51,45 +52,130 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
modulestore
=
self
.
store
modulestore
=
self
.
store
)
)
def
assertBlockDoesntExist
(
self
):
def
assertBlockDoesntExist
(
self
,
block_usage_key
,
draft
=
None
):
with
self
.
assertRaises
(
ItemNotFoundError
):
"""
self
.
store
.
get_item
(
self
.
block_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
Verify that loading ``block_usage_key`` raises an ItemNotFoundError.
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_item
(
self
.
block_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
draft_only
)
Arguments:
block_usage_key: The xblock to check.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
if
draft
is
None
or
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_item
(
self
.
block_usage_key
)
self
.
store
.
get_item
(
block_usage_key
)
if
draft
is
None
or
not
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_item
(
self
.
block_usage_key
)
self
.
store
.
get_item
(
block_usage_key
)
def
assertBlockHasContent
(
self
,
test_data
,
content
):
def
assertBlockHasContent
(
self
,
block_usage_key
,
field_name
,
content
,
draft
=
None
):
"""
Assert that the block ``block_usage_key`` has the value ``content`` for ``field_name``
when it is loaded.
Arguments:
block_usage_key: The xblock to check.
field_name (string): The name of the field to check.
content: The value to assert is in the field.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
if
draft
is
None
or
not
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
target_block
=
self
.
store
.
get_item
(
target_block
=
self
.
store
.
get_item
(
self
.
block_usage_key
,
block_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
)
self
.
assertEquals
(
content
,
target_block
.
fields
[
field_name
]
.
read_from
(
target_block
))
self
.
assertEquals
(
content
,
target_block
.
fields
[
test_data
.
field_name
]
.
read_from
(
target_block
))
if
draft
is
None
or
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
target_block
=
self
.
store
.
get_item
(
target_block
=
self
.
store
.
get_item
(
self
.
block_usage_key
,
block_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
draft_only
)
)
self
.
assertEquals
(
content
,
target_block
.
fields
[
test_data
.
field_name
]
.
read_from
(
target_block
))
self
.
assertEquals
(
content
,
target_block
.
fields
[
field_name
]
.
read_from
(
target_block
))
def
assertParentOf
(
self
,
parent_usage_key
,
child_usage_key
,
draft
=
None
):
"""
Assert that the block ``parent_usage_key`` has ``child_usage_key`` listed
as one of its ``.children``.
Arguments:
parent_usage_key: The xblock to check as a parent.
child_usage_key: The xblock to check as a child.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
if
draft
is
None
or
not
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
parent_block
=
self
.
store
.
get_item
(
parent_usage_key
,
)
self
.
assertIn
(
child_usage_key
,
parent_block
.
children
)
if
draft
is
None
or
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
targe
t_block
=
self
.
store
.
get_item
(
paren
t_block
=
self
.
store
.
get_item
(
self
.
block
_usage_key
,
parent
_usage_key
,
)
)
self
.
assertEquals
(
content
,
target_block
.
fields
[
test_data
.
field_name
]
.
read_from
(
target_block
)
)
self
.
assertIn
(
child_usage_key
,
parent_block
.
children
)
def
assertNotParentOf
(
self
,
parent_usage_key
,
child_usage_key
,
draft
=
None
):
"""
Assert that the block ``parent_usage_key`` does not have ``child_usage_key`` listed
as one of its ``.children``.
Arguments:
parent_usage_key: The xblock to check as a parent.
child_usage_key: The xblock to check as a child.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
if
draft
is
None
or
not
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
published_only
):
targe
t_block
=
self
.
store
.
get_item
(
paren
t_block
=
self
.
store
.
get_item
(
self
.
block
_usage_key
,
parent
_usage_key
,
)
)
self
.
assertEquals
(
content
,
target_block
.
fields
[
test_data
.
field_name
]
.
read_from
(
target_block
))
self
.
assertNotIn
(
child_usage_key
,
parent_block
.
children
)
if
draft
is
None
or
draft
:
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
parent_block
=
self
.
store
.
get_item
(
parent_usage_key
,
)
self
.
assertNotIn
(
child_usage_key
,
parent_block
.
children
)
def
assertCoursePointsToBlock
(
self
,
block_usage_key
,
draft
=
None
):
"""
Assert that the context course for the test has ``block_usage_key`` listed
as one of its ``.children``.
Arguments:
block_usage_key: The xblock to check.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
self
.
assertParentOf
(
self
.
course
.
scope_ids
.
usage_id
,
block_usage_key
,
draft
=
draft
)
def
assertCourseDoesntPointToBlock
(
self
,
block_usage_key
,
draft
=
None
):
"""
Assert that the context course for the test does not have ``block_usage_key`` listed
as one of its ``.children``.
Arguments:
block_usage_key: The xblock to check.
draft (optional): If omitted, verify both published and draft branches.
If True, verify only the draft branch. If False, verify only the
published branch.
"""
self
.
assertNotParentOf
(
self
.
course
.
scope_ids
.
usage_id
,
block_usage_key
,
draft
=
draft
)
def
is_detached
(
self
,
block_type
):
def
is_detached
(
self
,
block_type
):
"""
"""
...
@@ -109,9 +195,10 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
...
@@ -109,9 +195,10 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
and then verify that it was created successfully, and is visible in
and then verify that it was created successfully, and is visible in
both published and draft branches.
both published and draft branches.
"""
"""
self
.
block_usage_key
=
self
.
course
.
id
.
make_usage_key
(
block_type
,
'test_block'
)
block_usage_key
=
self
.
course
.
id
.
make_usage_key
(
block_type
,
'test_block'
)
self
.
assertBlockDoesntExist
()
self
.
assertBlockDoesntExist
(
block_usage_key
)
self
.
assertCourseDoesntPointToBlock
(
block_usage_key
)
test_data
=
self
.
DATA_FIELDS
[
block_type
]
test_data
=
self
.
DATA_FIELDS
[
block_type
]
...
@@ -122,8 +209,8 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
...
@@ -122,8 +209,8 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
block
=
self
.
store
.
create_xblock
(
block
=
self
.
store
.
create_xblock
(
self
.
course
.
runtime
,
self
.
course
.
runtime
,
self
.
course
.
id
,
self
.
course
.
id
,
self
.
block_usage_key
.
block_type
,
block_usage_key
.
block_type
,
block_id
=
self
.
block_usage_key
.
block_id
block_id
=
block_usage_key
.
block_id
)
)
block
.
fields
[
test_data
.
field_name
]
.
write_to
(
block
,
initial_field_value
)
block
.
fields
[
test_data
.
field_name
]
.
write_to
(
block
,
initial_field_value
)
self
.
store
.
update_item
(
block
,
ModuleStoreEnum
.
UserID
.
test
,
allow_not_found
=
True
)
self
.
store
.
update_item
(
block
,
ModuleStoreEnum
.
UserID
.
test
,
allow_not_found
=
True
)
...
@@ -132,18 +219,24 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
...
@@ -132,18 +219,24 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
parent_usage_key
=
self
.
course
.
scope_ids
.
usage_id
,
parent_usage_key
=
self
.
course
.
scope_ids
.
usage_id
,
block_type
=
block_type
,
block_type
=
block_type
,
block_id
=
self
.
block_usage_key
.
block_id
,
block_id
=
block_usage_key
.
block_id
,
fields
=
{
test_data
.
field_name
:
initial_field_value
},
fields
=
{
test_data
.
field_name
:
initial_field_value
},
)
)
self
.
assertBlockHasContent
(
test_data
,
initial_field_value
)
if
self
.
is_detached
(
block_type
):
self
.
assertCourseDoesntPointToBlock
(
block_usage_key
)
else
:
self
.
assertCoursePointsToBlock
(
block_usage_key
)
self
.
assertBlockHasContent
(
block_usage_key
,
test_data
.
field_name
,
initial_field_value
)
return
block_usage_key
@ddt.data
(
*
TESTABLE_BLOCK_TYPES
)
@ddt.data
(
*
TESTABLE_BLOCK_TYPES
)
def
test_update
(
self
,
block_type
):
def
test_update
(
self
,
block_type
):
self
.
_do_create
(
block_type
)
block_usage_key
=
self
.
_do_create
(
block_type
)
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
block
=
self
.
store
.
get_item
(
self
.
block_usage_key
)
block
=
self
.
store
.
get_item
(
block_usage_key
)
test_data
=
self
.
DATA_FIELDS
[
block_type
]
test_data
=
self
.
DATA_FIELDS
[
block_type
]
...
@@ -154,16 +247,81 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
...
@@ -154,16 +247,81 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
self
.
store
.
update_item
(
block
,
ModuleStoreEnum
.
UserID
.
test
,
allow_not_found
=
True
)
self
.
store
.
update_item
(
block
,
ModuleStoreEnum
.
UserID
.
test
,
allow_not_found
=
True
)
self
.
assertBlockHasContent
(
test_data
,
updated_field_value
)
self
.
assertBlockHasContent
(
block_usage_key
,
test_data
.
field_name
,
updated_field_value
)
@ddt.data
(
*
TESTABLE_BLOCK_TYPES
)
@ddt.data
(
*
TESTABLE_BLOCK_TYPES
)
def
test_delete
(
self
,
block_type
):
def
test_delete
(
self
,
block_type
):
self
.
_do_create
(
block_type
)
block_usage_key
=
self
.
_do_create
(
block_type
)
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
self
.
store
.
delete_item
(
block_usage_key
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
assertCourseDoesntPointToBlock
(
block_usage_key
)
self
.
assertBlockDoesntExist
(
block_usage_key
)
@ddt.data
(
*
itertools
.
product
([
'chapter'
,
'sequential'
],
[
True
,
False
]))
@ddt.unpack
def
test_delete_child
(
self
,
block_type
,
child_published
):
block_usage_key
=
self
.
course
.
id
.
make_usage_key
(
block_type
,
'test_block'
)
child_usage_key
=
self
.
course
.
id
.
make_usage_key
(
'html'
,
'test_child'
)
self
.
assertCourseDoesntPointToBlock
(
block_usage_key
)
self
.
assertBlockDoesntExist
(
block_usage_key
)
self
.
assertBlockDoesntExist
(
child_usage_key
)
test_data
=
self
.
DATA_FIELDS
[
block_type
]
child_data
=
'<div>child value</div>'
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
self
.
store
.
create_child
(
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
parent_usage_key
=
self
.
course
.
scope_ids
.
usage_id
,
block_type
=
block_type
,
block_id
=
block_usage_key
.
block_id
,
fields
=
{
test_data
.
field_name
:
test_data
.
initial
},
)
self
.
store
.
create_child
(
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
parent_usage_key
=
block_usage_key
,
block_type
=
child_usage_key
.
block_type
,
block_id
=
child_usage_key
.
block_id
,
fields
=
{
'data'
:
child_data
},
)
if
child_published
:
self
.
store
.
publish
(
child_usage_key
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
assertCoursePointsToBlock
(
block_usage_key
)
if
child_published
:
self
.
assertParentOf
(
block_usage_key
,
child_usage_key
)
else
:
self
.
assertParentOf
(
block_usage_key
,
child_usage_key
,
draft
=
True
)
# N.B. whether the direct-only parent block points to the child in the publish branch
# is left as undefined behavior
self
.
assertBlockHasContent
(
block_usage_key
,
test_data
.
field_name
,
test_data
.
initial
)
if
child_published
:
self
.
assertBlockHasContent
(
child_usage_key
,
'data'
,
child_data
)
else
:
self
.
assertBlockHasContent
(
child_usage_key
,
'data'
,
child_data
,
draft
=
True
)
self
.
assertBlockDoesntExist
(
child_usage_key
,
draft
=
False
)
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
self
.
store
.
delete_item
(
self
.
block_usage_key
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
store
.
delete_item
(
child_usage_key
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
assertCoursePointsToBlock
(
block_usage_key
)
self
.
assertNotParentOf
(
block_usage_key
,
child_usage_key
)
self
.
assertBlockDoesntExist
()
if
child_published
and
self
.
store
.
get_modulestore_type
(
self
.
course
.
id
)
==
ModuleStoreEnum
.
Type
.
mongo
:
# N.B. This block is being left as an orphan in old-mongo. This test will
# fail when that is fixed. At that time, this condition should just be removed,
# as SplitMongo and OldMongo will have the same semantics.
self
.
assertBlockHasContent
(
child_usage_key
,
'data'
,
child_data
)
else
:
self
.
assertBlockDoesntExist
(
child_usage_key
)
class
TestSplitDirectOnlyCategorySemantics
(
DirectOnlyCategorySemantics
):
class
TestSplitDirectOnlyCategorySemantics
(
DirectOnlyCategorySemantics
):
...
...
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