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
eeac479c
Commit
eeac479c
authored
May 28, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3901 from edx/dhm/opaque-dont-skip
Dhm/opaque dont skip
parents
8809c5f0
62bccd4e
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
221 additions
and
120 deletions
+221
-120
cms/djangoapps/contentstore/tests/test_crud.py
+1
-1
common/djangoapps/student/tests/test_email.py
+0
-1
common/lib/xmodule/xmodule/modulestore/split_migrator.py
+17
-17
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
+10
-2
common/lib/xmodule/xmodule/modulestore/split_mongo/definition_lazy_loader.py
+2
-1
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+135
-48
common/lib/xmodule/xmodule/modulestore/split_mongo/split_mongo_kvs.py
+2
-1
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
+4
-17
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
+50
-32
No files found.
cms/djangoapps/contentstore/tests/test_crud.py
View file @
eeac479c
...
@@ -68,7 +68,7 @@ class TemplateTests(unittest.TestCase):
...
@@ -68,7 +68,7 @@ class TemplateTests(unittest.TestCase):
self
.
assertIsInstance
(
test_chapter
,
SequenceDescriptor
)
self
.
assertIsInstance
(
test_chapter
,
SequenceDescriptor
)
# refetch parent which should now point to child
# refetch parent which should now point to child
test_course
=
modulestore
(
'split'
)
.
get_course
(
test_course
.
id
.
version_agnostic
())
test_course
=
modulestore
(
'split'
)
.
get_course
(
test_course
.
id
.
version_agnostic
())
self
.
assertIn
(
test_chapter
.
location
.
block_id
,
test_course
.
children
)
self
.
assertIn
(
test_chapter
.
location
,
test_course
.
children
)
with
self
.
assertRaises
(
DuplicateCourseError
):
with
self
.
assertRaises
(
DuplicateCourseError
):
persistent_factories
.
PersistentCourseFactory
.
create
(
persistent_factories
.
PersistentCourseFactory
.
create
(
...
...
common/djangoapps/student/tests/test_email.py
View file @
eeac479c
...
@@ -11,7 +11,6 @@ from django.test.client import RequestFactory
...
@@ -11,7 +11,6 @@ from django.test.client import RequestFactory
from
mock
import
Mock
,
patch
from
mock
import
Mock
,
patch
from
django.http
import
Http404
,
HttpResponse
from
django.http
import
Http404
,
HttpResponse
from
django.conf
import
settings
from
django.conf
import
settings
from
nose.plugins.skip
import
SkipTest
from
edxmako.shortcuts
import
render_to_string
from
edxmako.shortcuts
import
render_to_string
from
util.request
import
safe_get_host
from
util.request
import
safe_get_host
from
textwrap
import
dedent
from
textwrap
import
dedent
...
...
common/lib/xmodule/xmodule/modulestore/split_migrator.py
View file @
eeac479c
...
@@ -127,15 +127,15 @@ class SplitMigrator(object):
...
@@ -127,15 +127,15 @@ class SplitMigrator(object):
block_id
=
new_locator
.
block_id
,
block_id
=
new_locator
.
block_id
,
fields
=
self
.
_get_json_fields_translate_references
(
module
,
course_key
,
True
)
fields
=
self
.
_get_json_fields_translate_references
(
module
,
course_key
,
True
)
)
)
awaiting_adoption
[
module
.
location
]
=
new_locator
.
block_id
awaiting_adoption
[
module
.
location
]
=
new_locator
for
draft_location
,
new_
block_id
in
awaiting_adoption
.
iteritems
():
for
draft_location
,
new_
locator
in
awaiting_adoption
.
iteritems
():
for
parent_loc
in
self
.
draft_modulestore
.
get_parent_locations
(
draft_location
):
for
parent_loc
in
self
.
draft_modulestore
.
get_parent_locations
(
draft_location
):
old_parent
=
self
.
draft_modulestore
.
get_item
(
parent_loc
)
old_parent
=
self
.
draft_modulestore
.
get_item
(
parent_loc
)
new_parent
=
self
.
split_modulestore
.
get_item
(
new_parent
=
self
.
split_modulestore
.
get_item
(
self
.
loc_mapper
.
translate_location
(
old_parent
.
location
,
False
)
self
.
loc_mapper
.
translate_location
(
old_parent
.
location
,
False
)
)
)
# this only occurs if the parent was also awaiting adoption
# this only occurs if the parent was also awaiting adoption
if
new_block_id
in
new_parent
.
children
:
if
any
(
new_locator
==
child
.
version_agnostic
()
for
child
in
new_parent
.
children
)
:
break
break
# find index for module: new_parent may be missing quite a few of old_parent's children
# find index for module: new_parent may be missing quite a few of old_parent's children
new_parent_cursor
=
0
new_parent_cursor
=
0
...
@@ -145,36 +145,36 @@ class SplitMigrator(object):
...
@@ -145,36 +145,36 @@ class SplitMigrator(object):
sibling_loc
=
self
.
loc_mapper
.
translate_location
(
old_child_loc
,
False
)
sibling_loc
=
self
.
loc_mapper
.
translate_location
(
old_child_loc
,
False
)
# sibling may move cursor
# sibling may move cursor
for
idx
in
range
(
new_parent_cursor
,
len
(
new_parent
.
children
)):
for
idx
in
range
(
new_parent_cursor
,
len
(
new_parent
.
children
)):
if
new_parent
.
children
[
idx
]
==
sibling_loc
.
block_id
:
if
new_parent
.
children
[
idx
]
.
version_agnostic
()
==
sibling_loc
:
new_parent_cursor
=
idx
+
1
new_parent_cursor
=
idx
+
1
break
break
new_parent
.
children
.
insert
(
new_parent_cursor
,
new_
block_id
)
new_parent
.
children
.
insert
(
new_parent_cursor
,
new_
locator
)
new_parent
=
self
.
split_modulestore
.
update_item
(
new_parent
,
user
.
id
)
new_parent
=
self
.
split_modulestore
.
update_item
(
new_parent
,
user
.
id
)
def
_get_json_fields_translate_references
(
self
,
xblock
,
old_course_id
,
published
):
def
_get_json_fields_translate_references
(
self
,
xblock
,
old_course_id
,
published
):
"""
"""
Return the json repr for explicitly set fields but convert all references to their block_id's
Return the json repr for explicitly set fields but convert all references to their block_id's
"""
"""
# FIXME change split to take field values as pythonic values not json values
def
get_translation
(
location
):
"""
Convert the location and add to loc mapper
"""
return
self
.
loc_mapper
.
translate_location
(
location
,
published
,
add_entry_if_missing
=
True
)
result
=
{}
result
=
{}
for
field_name
,
field
in
xblock
.
fields
.
iteritems
():
for
field_name
,
field
in
xblock
.
fields
.
iteritems
():
if
field
.
is_set_on
(
xblock
):
if
field
.
is_set_on
(
xblock
):
if
isinstance
(
field
,
Reference
):
field_value
=
getattr
(
xblock
,
field_name
)
result
[
field_name
]
=
unicode
(
self
.
loc_mapper
.
translate_location
(
if
isinstance
(
field
,
Reference
)
and
field_value
is
not
None
:
getattr
(
xblock
,
field_name
),
published
,
add_entry_if_missing
=
True
result
[
field_name
]
=
get_translation
(
field_value
)
))
elif
isinstance
(
field
,
ReferenceList
):
elif
isinstance
(
field
,
ReferenceList
):
result
[
field_name
]
=
[
result
[
field_name
]
=
[
unicode
(
self
.
loc_mapper
.
translate_location
(
get_translation
(
ele
)
for
ele
in
field_value
ele
,
published
,
add_entry_if_missing
=
True
))
for
ele
in
getattr
(
xblock
,
field_name
)
]
]
elif
isinstance
(
field
,
ReferenceValueDict
):
elif
isinstance
(
field
,
ReferenceValueDict
):
result
[
field_name
]
=
{
result
[
field_name
]
=
{
key
:
unicode
(
self
.
loc_mapper
.
translate_location
(
key
:
get_translation
(
subvalue
)
subvalue
,
published
,
add_entry_if_missing
=
True
for
key
,
subvalue
in
field_value
.
iteritems
()
))
for
key
,
subvalue
in
getattr
(
xblock
,
field_name
)
.
iteritems
()
}
}
else
:
else
:
result
[
field_name
]
=
field
.
read_json
(
xblock
)
result
[
field_name
]
=
field
.
read_json
(
xblock
)
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
View file @
eeac479c
...
@@ -66,7 +66,12 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
...
@@ -66,7 +66,12 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
json_data
=
self
.
module_data
.
get
(
block_id
)
json_data
=
self
.
module_data
.
get
(
block_id
)
if
json_data
is
None
:
if
json_data
is
None
:
# deeper than initial descendant fetch or doesn't exist
# deeper than initial descendant fetch or doesn't exist
self
.
modulestore
.
cache_items
(
self
,
[
block_id
],
lazy
=
self
.
lazy
)
course_info
=
course_entry_override
or
self
.
course_entry
course_key
=
CourseLocator
(
course_info
.
get
(
'org'
),
course_info
.
get
(
'offering'
),
course_info
.
get
(
'branch'
),
course_info
[
'structure'
][
'_id'
]
)
self
.
modulestore
.
cache_items
(
self
,
[
block_id
],
course_key
,
lazy
=
self
.
lazy
)
json_data
=
self
.
module_data
.
get
(
block_id
)
json_data
=
self
.
module_data
.
get
(
block_id
)
if
json_data
is
None
:
if
json_data
is
None
:
raise
ItemNotFoundError
(
block_id
)
raise
ItemNotFoundError
(
block_id
)
...
@@ -112,9 +117,12 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
...
@@ -112,9 +117,12 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
block_id
=
block_id
,
block_id
=
block_id
,
)
)
converted_fields
=
self
.
modulestore
.
convert_references_to_keys
(
block_locator
.
course_key
,
class_
,
json_data
.
get
(
'fields'
,
{}),
self
.
course_entry
[
'structure'
][
'blocks'
],
)
kvs
=
SplitMongoKVS
(
kvs
=
SplitMongoKVS
(
definition
,
definition
,
json_data
.
get
(
'fields'
,
{})
,
converted_fields
,
json_data
.
get
(
'_inherited_settings'
),
json_data
.
get
(
'_inherited_settings'
),
)
)
field_data
=
KvsFieldData
(
kvs
)
field_data
=
KvsFieldData
(
kvs
)
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/definition_lazy_loader.py
View file @
eeac479c
...
@@ -8,7 +8,7 @@ class DefinitionLazyLoader(object):
...
@@ -8,7 +8,7 @@ class DefinitionLazyLoader(object):
object doesn't force access during init but waits until client wants the
object doesn't force access during init but waits until client wants the
definition. Only works if the modulestore is a split mongo store.
definition. Only works if the modulestore is a split mongo store.
"""
"""
def
__init__
(
self
,
modulestore
,
block_type
,
definition_id
):
def
__init__
(
self
,
modulestore
,
block_type
,
definition_id
,
field_converter
):
"""
"""
Simple placeholder for yet-to-be-fetched data
Simple placeholder for yet-to-be-fetched data
:param modulestore: the pymongo db connection with the definitions
:param modulestore: the pymongo db connection with the definitions
...
@@ -16,6 +16,7 @@ class DefinitionLazyLoader(object):
...
@@ -16,6 +16,7 @@ class DefinitionLazyLoader(object):
"""
"""
self
.
modulestore
=
modulestore
self
.
modulestore
=
modulestore
self
.
definition_locator
=
DefinitionLocator
(
block_type
,
definition_id
)
self
.
definition_locator
=
DefinitionLocator
(
block_type
,
definition_id
)
self
.
field_converter
=
field_converter
def
fetch
(
self
):
def
fetch
(
self
):
"""
"""
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
eeac479c
...
@@ -60,12 +60,12 @@ from xmodule.modulestore.locator import (
...
@@ -60,12 +60,12 @@ from xmodule.modulestore.locator import (
)
)
from
xmodule.modulestore.exceptions
import
InsufficientSpecificationError
,
VersionConflictError
,
DuplicateItemError
,
\
from
xmodule.modulestore.exceptions
import
InsufficientSpecificationError
,
VersionConflictError
,
DuplicateItemError
,
\
DuplicateCourseError
DuplicateCourseError
from
xmodule.modulestore
import
inheritance
,
ModuleStoreWriteBase
,
Location
,
SPLIT_MONGO_MODULESTORE_TYPE
from
xmodule.modulestore
import
inheritance
,
ModuleStoreWriteBase
,
SPLIT_MONGO_MODULESTORE_TYPE
from
..exceptions
import
ItemNotFoundError
from
..exceptions
import
ItemNotFoundError
from
.definition_lazy_loader
import
DefinitionLazyLoader
from
.definition_lazy_loader
import
DefinitionLazyLoader
from
.caching_descriptor_system
import
CachingDescriptorSystem
from
.caching_descriptor_system
import
CachingDescriptorSystem
from
xblock.fields
import
Scope
from
xblock.fields
import
Scope
,
Reference
,
ReferenceList
,
ReferenceValueDict
from
bson.objectid
import
ObjectId
from
bson.objectid
import
ObjectId
from
xmodule.modulestore.split_mongo.mongo_connection
import
MongoConnection
from
xmodule.modulestore.split_mongo.mongo_connection
import
MongoConnection
from
xblock.core
import
XBlock
from
xblock.core
import
XBlock
...
@@ -132,12 +132,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -132,12 +132,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
self
.
render_template
=
render_template
self
.
render_template
=
render_template
self
.
i18n_service
=
i18n_service
self
.
i18n_service
=
i18n_service
def
cache_items
(
self
,
system
,
base_block_ids
,
depth
=
0
,
lazy
=
True
):
def
cache_items
(
self
,
system
,
base_block_ids
,
course_key
,
depth
=
0
,
lazy
=
True
):
'''
'''
Handles caching of items once inheritance and any other one time
Handles caching of items once inheritance and any other one time
per course per fetch operations are done.
per course per fetch operations are done.
:param system: a CachingDescriptorSystem
:param system: a CachingDescriptorSystem
:param base_block_ids: list of block_ids to fetch
:param base_block_ids: list of block_ids to fetch
:param course_key: the destination course providing the context
:param depth: how deep below these to prefetch
:param depth: how deep below these to prefetch
:param lazy: whether to fetch definitions or use placeholders
:param lazy: whether to fetch definitions or use placeholders
'''
'''
...
@@ -152,7 +153,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -152,7 +153,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if
lazy
:
if
lazy
:
for
block
in
new_module_data
.
itervalues
():
for
block
in
new_module_data
.
itervalues
():
block
[
'definition'
]
=
DefinitionLazyLoader
(
self
,
block
[
'category'
],
block
[
'definition'
])
block
[
'definition'
]
=
DefinitionLazyLoader
(
self
,
block
[
'category'
],
block
[
'definition'
],
lambda
fields
:
self
.
convert_references_to_keys
(
course_key
,
system
.
load_block_type
(
block
[
'category'
]),
fields
,
system
.
course_entry
[
'structure'
][
'blocks'
],
)
)
else
:
else
:
# Load all descendants by id
# Load all descendants by id
descendent_definitions
=
self
.
db_connection
.
find_matching_definitions
({
descendent_definitions
=
self
.
db_connection
.
find_matching_definitions
({
...
@@ -164,7 +171,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -164,7 +171,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
for
block
in
new_module_data
.
itervalues
():
for
block
in
new_module_data
.
itervalues
():
if
block
[
'definition'
]
in
definitions
:
if
block
[
'definition'
]
in
definitions
:
block
[
'fields'
]
.
update
(
definitions
[
block
[
'definition'
]]
.
get
(
'fields'
))
converted_fields
=
self
.
convert_references_to_keys
(
course_key
,
system
.
load_block_type
(
block
[
'category'
]),
definitions
[
block
[
'definition'
]]
.
get
(
'fields'
),
system
.
course_entry
[
'structure'
][
'blocks'
],
)
block
[
'fields'
]
.
update
(
converted_fields
)
system
.
module_data
.
update
(
new_module_data
)
system
.
module_data
.
update
(
new_module_data
)
return
system
.
module_data
return
system
.
module_data
...
@@ -195,7 +207,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -195,7 +207,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
services
=
services
,
services
=
services
,
)
)
self
.
_add_cache
(
course_entry
[
'structure'
][
'_id'
],
system
)
self
.
_add_cache
(
course_entry
[
'structure'
][
'_id'
],
system
)
self
.
cache_items
(
system
,
block_ids
,
depth
,
lazy
)
course_key
=
CourseLocator
(
version_guid
=
course_entry
[
'structure'
][
'_id'
],
org
=
course_entry
.
get
(
'org'
),
offering
=
course_entry
.
get
(
'offering'
),
branch
=
course_entry
.
get
(
'branch'
),
)
self
.
cache_items
(
system
,
block_ids
,
course_key
,
depth
,
lazy
)
return
[
system
.
load_item
(
block_id
,
course_entry
)
for
block_id
in
block_ids
]
return
[
system
.
load_item
(
block_id
,
course_entry
)
for
block_id
in
block_ids
]
def
_get_cache
(
self
,
course_version_guid
):
def
_get_cache
(
self
,
course_version_guid
):
...
@@ -359,16 +377,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -359,16 +377,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
descendants.
descendants.
raises InsufficientSpecificationError or ItemNotFoundError
raises InsufficientSpecificationError or ItemNotFoundError
"""
"""
# intended for temporary support of some pointers being old-style
if
isinstance
(
usage_key
,
Location
):
if
self
.
loc_mapper
is
None
:
raise
InsufficientSpecificationError
(
'No location mapper configured'
)
else
:
usage_key
=
self
.
loc_mapper
.
translate_location
(
usage_key
,
usage_key
.
revision
is
None
,
add_entry_if_missing
=
False
)
assert
isinstance
(
usage_key
,
BlockUsageLocator
)
assert
isinstance
(
usage_key
,
BlockUsageLocator
)
course
=
self
.
_lookup_course
(
usage_key
)
course
=
self
.
_lookup_course
(
usage_key
)
items
=
self
.
_load_items
(
course
,
[
usage_key
.
block_id
],
depth
,
lazy
=
True
)
items
=
self
.
_load_items
(
course
,
[
usage_key
.
block_id
],
depth
,
lazy
=
True
)
...
@@ -631,7 +639,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -631,7 +639,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param user_id: request.user object
:param user_id: request.user object
"""
"""
new_def_data
=
self
.
_
filter_special_fields
(
new_def_data
)
new_def_data
=
self
.
_
serialize_fields
(
category
,
new_def_data
)
new_id
=
ObjectId
()
new_id
=
ObjectId
()
document
=
{
document
=
{
'_id'
:
new_id
,
'_id'
:
new_id
,
...
@@ -656,7 +664,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -656,7 +664,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param user_id: request.user
:param user_id: request.user
"""
"""
new_def_data
=
self
.
_filter_special_fields
(
new_def_data
)
def
needs_saved
():
def
needs_saved
():
for
key
,
value
in
new_def_data
.
iteritems
():
for
key
,
value
in
new_def_data
.
iteritems
():
if
key
not
in
old_definition
[
'fields'
]
or
value
!=
old_definition
[
'fields'
][
key
]:
if
key
not
in
old_definition
[
'fields'
]
or
value
!=
old_definition
[
'fields'
][
key
]:
...
@@ -669,8 +676,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -669,8 +676,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# actual change b/c the descriptor and cache probably point to the same objects
# actual change b/c the descriptor and cache probably point to the same objects
old_definition
=
self
.
db_connection
.
get_definition
(
definition_locator
.
definition_id
)
old_definition
=
self
.
db_connection
.
get_definition
(
definition_locator
.
definition_id
)
if
old_definition
is
None
:
if
old_definition
is
None
:
raise
ItemNotFoundError
(
definition_locator
.
to_deprecated_string
()
)
raise
ItemNotFoundError
(
definition_locator
)
new_def_data
=
self
.
_serialize_fields
(
old_definition
[
'category'
],
new_def_data
)
if
needs_saved
():
if
needs_saved
():
# new id to create new version
# new id to create new version
old_definition
[
'_id'
]
=
ObjectId
()
old_definition
[
'_id'
]
=
ObjectId
()
...
@@ -791,7 +799,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -791,7 +799,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
self
.
_update_block_in_structure
(
new_structure
,
new_block_id
,
{
self
.
_update_block_in_structure
(
new_structure
,
new_block_id
,
{
"category"
:
category
,
"category"
:
category
,
"definition"
:
definition_locator
.
definition_id
,
"definition"
:
definition_locator
.
definition_id
,
"fields"
:
block_fields
,
"fields"
:
self
.
_serialize_fields
(
category
,
block_fields
)
,
'edit_info'
:
{
'edit_info'
:
{
'edited_on'
:
datetime
.
datetime
.
now
(
UTC
),
'edited_on'
:
datetime
.
datetime
.
now
(
UTC
),
'edited_by'
:
user_id
,
'edited_by'
:
user_id
,
...
@@ -891,7 +899,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -891,7 +899,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block_fields
=
partitioned_fields
.
setdefault
(
Scope
.
settings
,
{})
block_fields
=
partitioned_fields
.
setdefault
(
Scope
.
settings
,
{})
if
Scope
.
children
in
partitioned_fields
:
if
Scope
.
children
in
partitioned_fields
:
block_fields
.
update
(
partitioned_fields
[
Scope
.
children
])
block_fields
.
update
(
partitioned_fields
[
Scope
.
children
])
definition_fields
=
self
.
_
filter_special_fields
(
partitioned_fields
.
get
(
Scope
.
content
,
{}))
definition_fields
=
self
.
_
serialize_fields
(
root_category
,
partitioned_fields
.
get
(
Scope
.
content
,
{}))
# build from inside out: definition, structure, index entry
# build from inside out: definition, structure, index entry
# if building a wholly new structure
# if building a wholly new structure
...
@@ -934,7 +942,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -934,7 +942,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
draft_structure
[
'root'
])
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
draft_structure
[
'root'
])
root_block
=
draft_structure
[
'blocks'
][
encoded_block_id
]
root_block
=
draft_structure
[
'blocks'
][
encoded_block_id
]
if
block_fields
is
not
None
:
if
block_fields
is
not
None
:
root_block
[
'fields'
]
.
update
(
block_fields
)
root_block
[
'fields'
]
.
update
(
self
.
_serialize_fields
(
root_category
,
block_fields
)
)
if
definition_fields
is
not
None
:
if
definition_fields
is
not
None
:
definition
=
self
.
db_connection
.
get_definition
(
root_block
[
'definition'
])
definition
=
self
.
db_connection
.
get_definition
(
root_block
[
'definition'
])
definition
[
'fields'
]
.
update
(
definition_fields
)
definition
[
'fields'
]
.
update
(
definition_fields
)
...
@@ -985,17 +993,20 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -985,17 +993,20 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
descriptor
.
definition_locator
,
is_updated
=
self
.
update_definition_from_data
(
descriptor
.
definition_locator
,
is_updated
=
self
.
update_definition_from_data
(
descriptor
.
definition_locator
,
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
),
user_id
)
descriptor
.
definition_locator
,
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
),
user_id
)
# check children
original_entry
=
self
.
_get_block_from_structure
(
original_structure
,
descriptor
.
location
.
block_id
)
original_entry
=
self
.
_get_block_from_structure
(
original_structure
,
descriptor
.
location
.
block_id
)
is_updated
=
is_updated
or
(
descriptor
.
has_children
and
original_entry
[
'fields'
]
.
get
(
'children'
,
[])
!=
descriptor
.
children
)
# check metadata
# check metadata
settings
=
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
settings
=
self
.
_serialize_fields
(
descriptor
.
category
,
settings
)
if
not
is_updated
:
if
not
is_updated
:
is_updated
=
self
.
_compare_settings
(
is_updated
=
self
.
_compare_settings
(
settings
,
original_entry
[
'fields'
])
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
),
original_entry
[
'fields'
]
# check children
)
if
descriptor
.
has_children
:
serialized_children
=
[
child
.
block_id
for
child
in
descriptor
.
children
]
is_updated
=
is_updated
or
original_entry
[
'fields'
]
.
get
(
'children'
,
[])
!=
serialized_children
if
is_updated
:
settings
[
'children'
]
=
serialized_children
# if updated, rev the structure
# if updated, rev the structure
if
is_updated
:
if
is_updated
:
...
@@ -1003,9 +1014,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1003,9 +1014,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block_data
=
self
.
_get_block_from_structure
(
new_structure
,
descriptor
.
location
.
block_id
)
block_data
=
self
.
_get_block_from_structure
(
new_structure
,
descriptor
.
location
.
block_id
)
block_data
[
"definition"
]
=
descriptor
.
definition_locator
.
definition_id
block_data
[
"definition"
]
=
descriptor
.
definition_locator
.
definition_id
block_data
[
"fields"
]
=
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
block_data
[
"fields"
]
=
settings
if
descriptor
.
has_children
:
block_data
[
'fields'
][
"children"
]
=
descriptor
.
children
new_id
=
new_structure
[
'_id'
]
new_id
=
new_structure
[
'_id'
]
block_data
[
'edit_info'
]
=
{
block_data
[
'edit_info'
]
=
{
...
@@ -1105,7 +1114,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1105,7 +1114,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
def
_persist_subdag
(
self
,
xblock
,
user_id
,
structure_blocks
,
new_id
):
def
_persist_subdag
(
self
,
xblock
,
user_id
,
structure_blocks
,
new_id
):
# persist the definition if persisted != passed
# persist the definition if persisted != passed
new_def_data
=
self
.
_
filter_special_fields
(
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
))
new_def_data
=
self
.
_
serialize_fields
(
xblock
.
category
,
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
))
is_updated
=
False
is_updated
=
False
if
xblock
.
definition_locator
is
None
or
isinstance
(
xblock
.
definition_locator
.
definition_id
,
LocalId
):
if
xblock
.
definition_locator
is
None
or
isinstance
(
xblock
.
definition_locator
.
definition_id
,
LocalId
):
xblock
.
definition_locator
=
self
.
create_definition_from_data
(
xblock
.
definition_locator
=
self
.
create_definition_from_data
(
...
@@ -1137,10 +1146,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1137,10 +1146,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
is_updated
=
self
.
_persist_subdag
(
child_block
,
user_id
,
structure_blocks
,
new_id
)
or
is_updated
is_updated
=
self
.
_persist_subdag
(
child_block
,
user_id
,
structure_blocks
,
new_id
)
or
is_updated
children
.
append
(
child_block
.
location
.
block_id
)
children
.
append
(
child_block
.
location
.
block_id
)
else
:
else
:
children
.
append
(
child
)
children
.
append
(
child
.
block_id
)
is_updated
=
is_updated
or
structure_blocks
[
encoded_block_id
][
'fields'
][
'children'
]
!=
children
is_updated
=
is_updated
or
structure_blocks
[
encoded_block_id
][
'fields'
][
'children'
]
!=
children
block_fields
=
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
block_fields
=
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
block_fields
=
self
.
_serialize_fields
(
xblock
.
category
,
block_fields
)
if
not
is_new
and
not
is_updated
:
if
not
is_new
and
not
is_updated
:
is_updated
=
self
.
_compare_settings
(
block_fields
,
structure_blocks
[
encoded_block_id
][
'fields'
])
is_updated
=
self
.
_compare_settings
(
block_fields
,
structure_blocks
[
encoded_block_id
][
'fields'
])
if
children
:
if
children
:
...
@@ -1204,12 +1214,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1204,12 +1214,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
Note, if the branch doesn't exist, then the source_course structure's root must be in subtree_list;
Note, if the branch doesn't exist, then the source_course structure's root must be in subtree_list;
otherwise, the publish will violate the parents must exist rule.
otherwise, the publish will violate the parents must exist rule.
:param subtree_list: a list of xblock ids whose subtrees to publish. The ids can be the block
:param subtree_list: a list of usage keys whose subtrees to publish.
id or BlockUsageLocator. If a Locator and if the Locator's course id != source_course, this will
raise InvalidLocationError(locator)
:param blacklist: a list of
xblock id
s to not change in the destination: i.e., don't add
:param blacklist: a list of
usage key
s to not change in the destination: i.e., don't add
if not there, don't update if there.
if not there, don't update if there.
Raises:
ItemNotFoundError: if it cannot find the course. if the request is to publish a
subtree but the ancestors up to and including the course root are not published.
"""
"""
# get the destination's index, and source and destination structures.
# get the destination's index, and source and destination structures.
source_structure
=
self
.
_lookup_course
(
source_course
)[
'structure'
]
source_structure
=
self
.
_lookup_course
(
source_course
)[
'structure'
]
...
@@ -1219,20 +1231,22 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1219,20 +1231,22 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
raise
ItemNotFoundError
(
destination_course
)
raise
ItemNotFoundError
(
destination_course
)
if
destination_course
.
branch
not
in
index_entry
[
'versions'
]:
if
destination_course
.
branch
not
in
index_entry
[
'versions'
]:
# must be publishing the dag root if there's no current dag
# must be publishing the dag root if there's no current dag
if
source_structure
[
'root'
]
not
in
subtree_list
:
root_block_id
=
source_structure
[
'root'
]
raise
ItemNotFoundError
(
source_structure
[
'root'
])
if
not
any
(
root_block_id
==
subtree
.
block_id
for
subtree
in
subtree_list
):
raise
ItemNotFoundError
(
u'Must publish course root {}'
.
format
(
root_block_id
))
# create branch
# create branch
destination_structure
=
self
.
_new_structure
(
user_id
,
source_structure
[
'root'
]
)
destination_structure
=
self
.
_new_structure
(
user_id
,
root_block_id
)
else
:
else
:
destination_structure
=
self
.
_lookup_course
(
destination_course
)[
'structure'
]
destination_structure
=
self
.
_lookup_course
(
destination_course
)[
'structure'
]
destination_structure
=
self
.
_version_structure
(
destination_structure
,
user_id
)
destination_structure
=
self
.
_version_structure
(
destination_structure
,
user_id
)
blacklist
=
[
shunned
.
block_id
for
shunned
in
blacklist
or
[]]
# iterate over subtree list filtering out blacklist.
# iterate over subtree list filtering out blacklist.
orphans
=
set
()
orphans
=
set
()
destination_blocks
=
destination_structure
[
'blocks'
]
destination_blocks
=
destination_structure
[
'blocks'
]
for
subtree_root
in
subtree_list
:
for
subtree_root
in
subtree_list
:
# find the parents and put root in the right sequence
# find the parents and put root in the right sequence
parents
=
self
.
_get_parents_from_structure
(
subtree_root
,
source_structure
)
parents
=
self
.
_get_parents_from_structure
(
subtree_root
.
block_id
,
source_structure
)
if
not
all
(
parent
in
destination_blocks
for
parent
in
parents
):
if
not
all
(
parent
in
destination_blocks
for
parent
in
parents
):
raise
ItemNotFoundError
(
parents
)
raise
ItemNotFoundError
(
parents
)
for
parent_loc
in
parents
:
for
parent_loc
in
parents
:
...
@@ -1240,12 +1254,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1240,12 +1254,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
self
.
_sync_children
(
self
.
_sync_children
(
source_structure
[
'blocks'
][
parent_loc
],
source_structure
[
'blocks'
][
parent_loc
],
destination_blocks
[
parent_loc
],
destination_blocks
[
parent_loc
],
subtree_root
subtree_root
.
block_id
))
))
# update/create the subtree and its children in destination (skipping blacklist)
# update/create the subtree and its children in destination (skipping blacklist)
orphans
.
update
(
orphans
.
update
(
self
.
_publish_subdag
(
self
.
_publish_subdag
(
user_id
,
subtree_root
,
source_structure
[
'blocks'
],
destination_blocks
,
blacklist
or
[]
user_id
,
subtree_root
.
block_id
,
source_structure
[
'blocks'
],
destination_blocks
,
blacklist
)
)
)
)
# remove any remaining orphans
# remove any remaining orphans
...
@@ -1444,6 +1458,47 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1444,6 +1458,47 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# clear cache again b/c inheritance may be wrong over orphans
# clear cache again b/c inheritance may be wrong over orphans
self
.
_clear_cache
(
original_structure
[
'_id'
])
self
.
_clear_cache
(
original_structure
[
'_id'
])
def
convert_references_to_keys
(
self
,
course_key
,
xblock_class
,
jsonfields
,
blocks
):
"""
Convert the given serialized fields to the deserialized values by finding all references
and converting them.
:param jsonfields: the serialized copy of the xblock's fields
"""
def
robust_usage_key
(
block_id
):
"""
create a course_key relative usage key for the block_id. If the block_id is in blocks,
use its correct category; otherwise, use 'unknown'.
The purpose for this is that some operations add pointers as they build up the
structure without worrying about order of creation. Because the category of the
usage_key is for the most part inert, it's better to hack a value than to work
out a dependency graph algorithm for those functions which may prereference blocks.
"""
# if this was taken from cache, then its fields are already converted
if
isinstance
(
block_id
,
BlockUsageLocator
):
return
block_id
try
:
return
course_key
.
make_usage_key
(
blocks
[
LocMapperStore
.
encode_key_for_mongo
(
block_id
)][
'category'
],
block_id
)
except
KeyError
:
return
course_key
.
make_usage_key
(
'unknown'
,
block_id
)
xblock_class
=
self
.
mixologist
.
mix
(
xblock_class
)
for
field_name
,
value
in
jsonfields
.
iteritems
():
if
value
:
field
=
xblock_class
.
fields
.
get
(
field_name
)
if
field
is
None
:
continue
elif
isinstance
(
field
,
Reference
):
jsonfields
[
field_name
]
=
robust_usage_key
(
value
)
elif
isinstance
(
field
,
ReferenceList
):
jsonfields
[
field_name
]
=
[
robust_usage_key
(
ele
)
for
ele
in
value
]
elif
isinstance
(
field
,
ReferenceValueDict
):
for
key
,
subvalue
in
value
.
iteritems
():
assert
isinstance
(
subvalue
,
basestring
)
value
[
key
]
=
robust_usage_key
(
subvalue
)
return
jsonfields
def
_get_index_if_valid
(
self
,
locator
,
force
=
False
,
continue_version
=
False
):
def
_get_index_if_valid
(
self
,
locator
,
force
=
False
,
continue_version
=
False
):
"""
"""
If the locator identifies a course and points to its draft (or plausibly its draft),
If the locator identifies a course and points to its draft (or plausibly its draft),
...
@@ -1514,15 +1569,36 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1514,15 +1569,36 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
index_entry
[
'versions'
][
branch
]
=
new_id
index_entry
[
'versions'
][
branch
]
=
new_id
self
.
db_connection
.
update_course_index
(
index_entry
)
self
.
db_connection
.
update_course_index
(
index_entry
)
def
_
filter_special_fields
(
self
,
fields
):
def
_
serialize_fields
(
self
,
category
,
fields
):
"""
"""
Convert any references to their serialized form.
Remove any fields which split or its kvs computes or adds but does not want persisted.
Remove any fields which split or its kvs computes or adds but does not want persisted.
:param fields: a dict of fields
:param fields: a dict of fields
"""
"""
assert
isinstance
(
fields
,
dict
)
xblock_class
=
XBlock
.
load_class
(
category
,
self
.
default_class
)
xblock_class
=
self
.
mixologist
.
mix
(
xblock_class
)
for
field_name
,
value
in
fields
.
iteritems
():
if
value
:
if
isinstance
(
xblock_class
.
fields
[
field_name
],
Reference
):
fields
[
field_name
]
=
value
.
block_id
elif
isinstance
(
xblock_class
.
fields
[
field_name
],
ReferenceList
):
fields
[
field_name
]
=
[
ele
.
block_id
for
ele
in
value
]
elif
isinstance
(
xblock_class
.
fields
[
field_name
],
ReferenceValueDict
):
for
key
,
subvalue
in
value
.
iteritems
():
assert
isinstance
(
subvalue
,
Location
)
value
[
key
]
=
subvalue
.
block_id
# I think these are obsolete conditions; so, I want to confirm that. Thus the warnings
if
'location'
in
fields
:
if
'location'
in
fields
:
log
.
warn
(
'attempt to persist location'
)
del
fields
[
'location'
]
del
fields
[
'location'
]
if
'category'
in
fields
:
if
'category'
in
fields
:
log
.
warn
(
'attempt to persist category'
)
del
fields
[
'category'
]
del
fields
[
'category'
]
return
fields
return
fields
...
@@ -1616,7 +1692,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1616,7 +1692,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
user_id
,
new_block
[
'category'
],
user_id
,
new_block
[
'category'
],
self
.
_filter_blacklist
(
copy
.
copy
(
new_block
[
'fields'
]),
blacklist
),
self
.
_filter_blacklist
(
copy
.
copy
(
new_block
[
'fields'
]),
blacklist
),
new_block
[
'definition'
],
new_block
[
'definition'
],
new_block
[
'edit_info'
][
'update_version'
]
new_block
[
'edit_info'
][
'update_version'
],
raw
=
True
)
)
for
child
in
destination_block
[
'fields'
]
.
get
(
'children'
,
[]):
for
child
in
destination_block
[
'fields'
]
.
get
(
'children'
,
[]):
if
child
not
in
blacklist
:
if
child
not
in
blacklist
:
...
@@ -1642,7 +1719,17 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1642,7 +1719,17 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
self
.
_delete_if_true_orphan
(
child
,
structure
)
self
.
_delete_if_true_orphan
(
child
,
structure
)
del
structure
[
'blocks'
][
encoded_block_id
]
del
structure
[
'blocks'
][
encoded_block_id
]
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
):
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
,
raw
=
False
):
"""
Create the core document structure for a block.
:param block_fields: the settings and children scoped fields as a dict or son
:param definition_id: the pointer to the content scoped fields
:param new_id: the structure's version id
:param raw: true if this block already has all references serialized
"""
if
not
raw
:
block_fields
=
self
.
_serialize_fields
(
category
,
block_fields
)
return
{
return
{
'category'
:
category
,
'category'
:
category
,
'definition'
:
definition_id
,
'definition'
:
definition_id
,
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split_mongo_kvs.py
View file @
eeac479c
...
@@ -110,6 +110,7 @@ class SplitMongoKVS(InheritanceKeyValueStore):
...
@@ -110,6 +110,7 @@ class SplitMongoKVS(InheritanceKeyValueStore):
if
isinstance
(
self
.
_definition
,
DefinitionLazyLoader
):
if
isinstance
(
self
.
_definition
,
DefinitionLazyLoader
):
persisted_definition
=
self
.
_definition
.
fetch
()
persisted_definition
=
self
.
_definition
.
fetch
()
if
persisted_definition
is
not
None
:
if
persisted_definition
is
not
None
:
self
.
_fields
.
update
(
persisted_definition
.
get
(
'fields'
))
fields
=
self
.
_definition
.
field_converter
(
persisted_definition
.
get
(
'fields'
))
self
.
_fields
.
update
(
fields
)
# do we want to cache any of the edit_info?
# do we want to cache any of the edit_info?
self
.
_definition
=
None
# already loaded
self
.
_definition
=
None
# already loaded
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
View file @
eeac479c
...
@@ -10,10 +10,9 @@ from xmodule.modulestore.split_migrator import SplitMigrator
...
@@ -10,10 +10,9 @@ from xmodule.modulestore.split_migrator import SplitMigrator
from
xmodule.modulestore.mongo
import
draft
from
xmodule.modulestore.mongo
import
draft
from
xmodule.modulestore.tests
import
test_location_mapper
from
xmodule.modulestore.tests
import
test_location_mapper
from
xmodule.modulestore.tests.test_split_w_old_mongo
import
SplitWMongoCourseBoostrapper
from
xmodule.modulestore.tests.test_split_w_old_mongo
import
SplitWMongoCourseBoostrapper
from
nose.tools
import
nottes
t
from
xblock.fields
import
Reference
,
ReferenceList
,
ReferenceValueDic
t
@nottest
class
TestMigration
(
SplitWMongoCourseBoostrapper
):
class
TestMigration
(
SplitWMongoCourseBoostrapper
):
"""
"""
Test the split migrator
Test the split migrator
...
@@ -181,8 +180,8 @@ class TestMigration(SplitWMongoCourseBoostrapper):
...
@@ -181,8 +180,8 @@ class TestMigration(SplitWMongoCourseBoostrapper):
self
.
loc_mapper
.
translate_locator_to_location
(
split_dag_root
.
location
)
.
replace
(
revision
=
None
)
self
.
loc_mapper
.
translate_locator_to_location
(
split_dag_root
.
location
)
.
replace
(
revision
=
None
)
)
)
# compare all fields but children
# compare all fields but children
for
name
in
presplit_dag_root
.
fields
.
iterkey
s
():
for
name
,
field
in
presplit_dag_root
.
fields
.
iteritem
s
():
if
n
ame
!=
'children'
:
if
n
ot
isinstance
(
field
,
(
Reference
,
ReferenceList
,
ReferenceValueDict
))
:
self
.
assertEqual
(
self
.
assertEqual
(
getattr
(
presplit_dag_root
,
name
),
getattr
(
presplit_dag_root
,
name
),
getattr
(
split_dag_root
,
name
),
getattr
(
split_dag_root
,
name
),
...
@@ -190,19 +189,7 @@ class TestMigration(SplitWMongoCourseBoostrapper):
...
@@ -190,19 +189,7 @@ class TestMigration(SplitWMongoCourseBoostrapper):
split_dag_root
.
location
,
name
,
getattr
(
presplit_dag_root
,
name
),
getattr
(
split_dag_root
,
name
)
split_dag_root
.
location
,
name
,
getattr
(
presplit_dag_root
,
name
),
getattr
(
split_dag_root
,
name
)
)
)
)
)
# test split get_item using old Location: old draft store didn't set revision for things above vertical
# but split does distinguish these; so, set revision if not published
if
not
published
:
location
=
draft
.
as_draft
(
presplit_dag_root
.
location
)
else
:
location
=
presplit_dag_root
.
location
refetched
=
self
.
split_mongo
.
get_item
(
location
)
self
.
assertEqual
(
refetched
.
location
,
split_dag_root
.
location
,
"Fetch from split via old Location {} not same as new {}"
.
format
(
refetched
.
location
,
split_dag_root
.
location
)
)
# compare children
# compare children
if
presplit_dag_root
.
has_children
:
if
presplit_dag_root
.
has_children
:
self
.
assertEqual
(
self
.
assertEqual
(
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
View file @
eeac479c
...
@@ -482,7 +482,7 @@ class SplitModuleTest(unittest.TestCase):
...
@@ -482,7 +482,7 @@ class SplitModuleTest(unittest.TestCase):
block_id
=
"head23456"
block_id
=
"head23456"
)
)
destination
=
CourseLocator
(
org
=
"testx"
,
offering
=
"wonderful"
,
branch
=
"published"
)
destination
=
CourseLocator
(
org
=
"testx"
,
offering
=
"wonderful"
,
branch
=
"published"
)
split_store
.
xblock_publish
(
"test@edx.org"
,
to_publish
,
destination
,
[
to_publish
.
block_id
],
None
)
split_store
.
xblock_publish
(
"test@edx.org"
,
to_publish
,
destination
,
[
to_publish
],
None
)
def
tearDown
(
self
):
def
tearDown
(
self
):
"""
"""
...
@@ -628,7 +628,9 @@ class SplitModuleCourseTests(SplitModuleTest):
...
@@ -628,7 +628,9 @@ class SplitModuleCourseTests(SplitModuleTest):
"""
"""
locator
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
locator
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
course
=
modulestore
()
.
get_course
(
locator
)
course
=
modulestore
()
.
get_course
(
locator
)
block_map
=
modulestore
()
.
cache_items
(
course
.
system
,
course
.
children
,
depth
=
3
)
block_map
=
modulestore
()
.
cache_items
(
course
.
system
,
[
child
.
block_id
for
child
in
course
.
children
],
course
.
id
,
depth
=
3
)
self
.
assertIn
(
'chapter1'
,
block_map
)
self
.
assertIn
(
'chapter1'
,
block_map
)
self
.
assertIn
(
'problem3_2'
,
block_map
)
self
.
assertIn
(
'problem3_2'
,
block_map
)
...
@@ -891,6 +893,10 @@ class SplitModuleItemTests(SplitModuleTest):
...
@@ -891,6 +893,10 @@ class SplitModuleItemTests(SplitModuleTest):
self
.
assertEqual
(
len
(
expected_ids
),
0
)
self
.
assertEqual
(
len
(
expected_ids
),
0
)
def
version_agnostic
(
children
):
return
[
child
.
version_agnostic
()
for
child
in
children
]
class
TestItemCrud
(
SplitModuleTest
):
class
TestItemCrud
(
SplitModuleTest
):
"""
"""
Test create update and delete of items
Test create update and delete of items
...
@@ -974,9 +980,10 @@ class TestItemCrud(SplitModuleTest):
...
@@ -974,9 +980,10 @@ class TestItemCrud(SplitModuleTest):
# check that course version changed and course's previous is the other one
# check that course version changed and course's previous is the other one
self
.
assertNotEqual
(
new_module
.
location
.
version_guid
,
premod_course
.
location
.
version_guid
)
self
.
assertNotEqual
(
new_module
.
location
.
version_guid
,
premod_course
.
location
.
version_guid
)
parent
=
modulestore
()
.
get_item
(
locator
)
parent
=
modulestore
()
.
get_item
(
locator
)
self
.
assertIn
(
new_module
.
location
.
block_id
,
parent
.
children
)
self
.
assertIn
(
new_module
.
location
.
version_agnostic
(),
version_agnostic
(
parent
.
children
)
)
self
.
assertEqual
(
new_module
.
definition_locator
.
definition_id
,
original
.
definition_locator
.
definition_id
)
self
.
assertEqual
(
new_module
.
definition_locator
.
definition_id
,
original
.
definition_locator
.
definition_id
)
def
test_unique_naming
(
self
):
def
test_unique_naming
(
self
):
"""
"""
Check that 2 modules of same type get unique block_ids. Also check that if creation provides
Check that 2 modules of same type get unique block_ids. Also check that if creation provides
...
@@ -1007,8 +1014,8 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1007,8 +1014,8 @@ class TestItemCrud(SplitModuleTest):
# check that course version changed and course's previous is the other one
# check that course version changed and course's previous is the other one
parent
=
modulestore
()
.
get_item
(
locator
)
parent
=
modulestore
()
.
get_item
(
locator
)
self
.
assertNotEqual
(
new_module
.
location
.
block_id
,
another_module
.
location
.
block_id
)
self
.
assertNotEqual
(
new_module
.
location
.
block_id
,
another_module
.
location
.
block_id
)
self
.
assertIn
(
new_module
.
location
.
block_id
,
parent
.
children
)
self
.
assertIn
(
new_module
.
location
.
version_agnostic
(),
version_agnostic
(
parent
.
children
)
)
self
.
assertIn
(
another_module
.
location
.
block_id
,
parent
.
children
)
self
.
assertIn
(
another_module
.
location
.
version_agnostic
(),
version_agnostic
(
parent
.
children
)
)
self
.
assertEqual
(
new_module
.
data
,
new_payload
)
self
.
assertEqual
(
new_module
.
data
,
new_payload
)
self
.
assertEqual
(
another_module
.
data
,
another_payload
)
self
.
assertEqual
(
another_module
.
data
,
another_payload
)
# check definition histories
# check definition histories
...
@@ -1046,7 +1053,7 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1046,7 +1053,7 @@ class TestItemCrud(SplitModuleTest):
new_module
=
modulestore
()
.
get_item
(
problem_locator
)
new_module
=
modulestore
()
.
get_item
(
problem_locator
)
self
.
assertEqual
(
new_module
.
location
.
block_id
,
problem_locator
.
block_id
)
self
.
assertEqual
(
new_module
.
location
.
block_id
,
problem_locator
.
block_id
)
chapter
=
modulestore
()
.
get_item
(
chapter_locator
)
chapter
=
modulestore
()
.
get_item
(
chapter_locator
)
self
.
assertIn
(
problem_locator
.
block_id
,
chapter
.
children
)
self
.
assertIn
(
problem_locator
,
version_agnostic
(
chapter
.
children
)
)
def
test_create_continue_version
(
self
):
def
test_create_continue_version
(
self
):
"""
"""
...
@@ -1077,7 +1084,7 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1077,7 +1084,7 @@ class TestItemCrud(SplitModuleTest):
self
.
assertEqual
(
refetch_course
.
update_version
,
course_block_update_version
)
self
.
assertEqual
(
refetch_course
.
update_version
,
course_block_update_version
)
refetch_index_history_info
=
modulestore
()
.
get_course_history_info
(
refetch_course
.
location
)
refetch_index_history_info
=
modulestore
()
.
get_course_history_info
(
refetch_course
.
location
)
self
.
assertEqual
(
refetch_index_history_info
,
index_history_info
)
self
.
assertEqual
(
refetch_index_history_info
,
index_history_info
)
self
.
assertIn
(
new_ele
.
location
.
block_id
,
refetch_course
.
children
)
self
.
assertIn
(
new_ele
.
location
.
version_agnostic
(),
version_agnostic
(
refetch_course
.
children
)
)
# try to create existing item
# try to create existing item
with
self
.
assertRaises
(
DuplicateItemError
):
with
self
.
assertRaises
(
DuplicateItemError
):
...
@@ -1123,7 +1130,7 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1123,7 +1130,7 @@ class TestItemCrud(SplitModuleTest):
# check children, previous_version
# check children, previous_version
refetch_course
=
modulestore
()
.
get_course
(
versionless_course_locator
)
refetch_course
=
modulestore
()
.
get_course
(
versionless_course_locator
)
self
.
assertIn
(
new_ele
.
location
.
block_id
,
refetch_course
.
children
)
self
.
assertIn
(
new_ele
.
location
.
version_agnostic
(),
version_agnostic
(
refetch_course
.
children
)
)
self
.
assertEqual
(
refetch_course
.
previous_version
,
course_block_update_version
)
self
.
assertEqual
(
refetch_course
.
previous_version
,
course_block_update_version
)
self
.
assertEqual
(
refetch_course
.
update_version
,
transaction_guid
)
self
.
assertEqual
(
refetch_course
.
update_version
,
transaction_guid
)
...
@@ -1180,13 +1187,13 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1180,13 +1187,13 @@ class TestItemCrud(SplitModuleTest):
# check that course version changed and course's previous is the other one
# check that course version changed and course's previous is the other one
self
.
assertEqual
(
updated_problem
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertEqual
(
updated_problem
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_problem
.
location
.
version_guid
,
pre_version_guid
)
self
.
assertNotEqual
(
updated_problem
.
location
.
version_guid
,
pre_version_guid
)
self
.
assertEqual
(
updated_problem
.
children
,
block
.
children
)
self
.
assertEqual
(
version_agnostic
(
updated_problem
.
children
),
version_agnostic
(
block
.
children
)
)
self
.
assertNotIn
(
moved_child
,
updated_problem
.
children
)
self
.
assertNotIn
(
moved_child
,
version_agnostic
(
updated_problem
.
children
)
)
locator
=
locator
.
course_key
.
make_usage_key
(
'Chapter'
,
"chapter1"
)
locator
=
locator
.
course_key
.
make_usage_key
(
'Chapter'
,
"chapter1"
)
other_block
=
modulestore
()
.
get_item
(
locator
)
other_block
=
modulestore
()
.
get_item
(
locator
)
other_block
.
children
.
append
(
moved_child
)
other_block
.
children
.
append
(
moved_child
)
other_updated
=
modulestore
()
.
update_item
(
other_block
,
'**replace_user**'
)
other_updated
=
modulestore
()
.
update_item
(
other_block
,
'**replace_user**'
)
self
.
assertIn
(
moved_child
,
other_updated
.
children
)
self
.
assertIn
(
moved_child
.
version_agnostic
(),
version_agnostic
(
other_updated
.
children
)
)
def
test_update_definition
(
self
):
def
test_update_definition
(
self
):
"""
"""
...
@@ -1251,7 +1258,7 @@ class TestItemCrud(SplitModuleTest):
...
@@ -1251,7 +1258,7 @@ class TestItemCrud(SplitModuleTest):
self
.
assertNotEqual
(
updated_block
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_block
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_block
.
location
.
version_guid
,
pre_version_guid
)
self
.
assertNotEqual
(
updated_block
.
location
.
version_guid
,
pre_version_guid
)
self
.
assertEqual
(
updated_block
.
grading_policy
[
'GRADER'
][
0
][
'min_count'
],
13
)
self
.
assertEqual
(
updated_block
.
grading_policy
[
'GRADER'
][
0
][
'min_count'
],
13
)
self
.
assertEqual
(
updated_block
.
children
[
0
]
,
block
.
children
[
0
]
)
self
.
assertEqual
(
updated_block
.
children
[
0
]
.
version_agnostic
(),
block
.
children
[
0
]
.
version_agnostic
()
)
self
.
assertEqual
(
updated_block
.
advertised_start
,
"Soon"
)
self
.
assertEqual
(
updated_block
.
advertised_start
,
"Soon"
)
def
test_delete_item
(
self
):
def
test_delete_item
(
self
):
...
@@ -1520,40 +1527,44 @@ class TestPublish(SplitModuleTest):
...
@@ -1520,40 +1527,44 @@ class TestPublish(SplitModuleTest):
"""
"""
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
dest_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
dest_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
"head12345"
],
[
"chapter2"
,
"chapter3"
])
head
=
source_course
.
make_usage_key
(
'course'
,
"head12345"
)
expected
=
[
"head12345"
,
"chapter1"
]
chapter1
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter1'
)
chapter2
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter2'
)
chapter3
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter3'
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
,
chapter3
])
expected
=
[
head
.
block_id
,
chapter1
.
block_id
]
self
.
_check_course
(
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
,
"chapter3"
,
"problem1"
,
"problem3_2"
]
source_course
,
dest_course
,
expected
,
[
chapter2
.
block_id
,
chapter3
.
block_id
,
"problem1"
,
"problem3_2"
]
)
)
# add a child under chapter1
# add a child under chapter1
new_module
=
modulestore
()
.
create_item
(
new_module
=
modulestore
()
.
create_item
(
BlockUsageLocator
.
make_relative
(
source_course
,
"chapter"
,
"chapter1"
)
,
"sequential"
,
self
.
user
,
chapter1
,
"sequential"
,
self
.
user
,
fields
=
{
'display_name'
:
'new sequential'
},
fields
=
{
'display_name'
:
'new sequential'
},
)
)
# remove chapter1 from expected b/c its pub'd version != the source anymore since source changed
# remove chapter1 from expected b/c its pub'd version != the source anymore since source changed
expected
.
remove
(
"chapter1"
)
expected
.
remove
(
chapter1
.
block_id
)
# check that it's not in published course
# check that it's not in published course
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
# publish it
# publish it
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
.
block_id
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
expected
.
append
(
new_module
.
location
.
block_id
)
expected
.
append
(
new_module
.
location
.
block_id
)
# check that it is in the published course and that its parent is the chapter
# check that it is in the published course and that its parent is the chapter
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
self
.
assertEqual
(
self
.
assertEqual
(
modulestore
()
.
get_parent_locations
(
pub_module
.
location
)[
0
]
.
block_id
,
"chapter1"
modulestore
()
.
get_parent_locations
(
pub_module
.
location
)[
0
]
.
block_id
,
chapter1
.
block_id
)
)
# ensure intentionally orphaned blocks work (e.g., course_info)
# ensure intentionally orphaned blocks work (e.g., course_info)
new_module
=
modulestore
()
.
create_item
(
new_module
=
modulestore
()
.
create_item
(
source_course
,
"course_info"
,
self
.
user
,
block_id
=
"handouts"
source_course
,
"course_info"
,
self
.
user
,
block_id
=
"handouts"
)
)
# publish it
# publish it
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
.
block_id
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
expected
.
append
(
new_module
.
location
.
block_id
)
expected
.
append
(
new_module
.
location
.
block_id
)
# check that it is in the published course (no error means it worked)
# check that it is in the published course (no error means it worked)
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
self
.
_check_course
(
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
,
"chapter3"
,
"problem1"
,
"problem3_2"
]
source_course
,
dest_course
,
expected
,
[
chapter2
.
block_id
,
chapter3
.
block_id
,
"problem1"
,
"problem3_2"
]
)
)
def
test_exceptions
(
self
):
def
test_exceptions
(
self
):
...
@@ -1563,16 +1574,19 @@ class TestPublish(SplitModuleTest):
...
@@ -1563,16 +1574,19 @@ class TestPublish(SplitModuleTest):
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
# destination does not exist
# destination does not exist
destination_course
=
CourseLocator
(
org
=
'fake'
,
offering
=
'Unknown'
,
branch
=
"published"
)
destination_course
=
CourseLocator
(
org
=
'fake'
,
offering
=
'Unknown'
,
branch
=
"published"
)
head
=
source_course
.
make_usage_key
(
'course'
,
"head12345"
)
chapter3
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter3'
)
problem1
=
source_course
.
make_usage_key
(
'problem'
,
'problem1'
)
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
"chapter3"
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
chapter3
],
None
)
# publishing into a new branch w/o publishing the root
# publishing into a new branch w/o publishing the root
destination_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
destination_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
"chapter3"
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
chapter3
],
None
)
# publishing a subdag w/o the parent already in course
# publishing a subdag w/o the parent already in course
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
"head12345"
],
[
"chapter3"
])
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
head
],
[
chapter3
])
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
"problem1"
],
[])
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
problem1
],
[])
def
test_move_delete
(
self
):
def
test_move_delete
(
self
):
"""
"""
...
@@ -1580,16 +1594,19 @@ class TestPublish(SplitModuleTest):
...
@@ -1580,16 +1594,19 @@ class TestPublish(SplitModuleTest):
"""
"""
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
source_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
'draft'
)
dest_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
dest_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
"published"
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
"head12345"
],
[
"chapter2"
])
head
=
source_course
.
make_usage_key
(
'course'
,
"head12345"
)
chapter2
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter2'
)
problem1
=
source_course
.
make_usage_key
(
'problem'
,
'problem1'
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
,
"problem3_2"
]
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
,
"problem3_2"
]
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
])
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
])
# now move problem1 and delete problem3_2
# now move problem1 and delete problem3_2
chapter1
=
modulestore
()
.
get_item
(
source_course
.
make_usage_key
(
"chapter"
,
"chapter1"
))
chapter1
=
modulestore
()
.
get_item
(
source_course
.
make_usage_key
(
"chapter"
,
"chapter1"
))
chapter3
=
modulestore
()
.
get_item
(
source_course
.
make_usage_key
(
"chapter"
,
"chapter3"
))
chapter3
=
modulestore
()
.
get_item
(
source_course
.
make_usage_key
(
"chapter"
,
"chapter3"
))
chapter1
.
children
.
append
(
"problem1"
)
chapter1
.
children
.
append
(
problem1
)
chapter3
.
children
.
remove
(
"problem1"
)
chapter3
.
children
.
remove
(
problem1
.
map_into_course
(
chapter3
.
location
.
course_key
)
)
modulestore
()
.
delete_item
(
source_course
.
make_usage_key
(
"problem"
,
"problem3_2"
),
self
.
user
)
modulestore
()
.
delete_item
(
source_course
.
make_usage_key
(
"problem"
,
"problem3_2"
),
self
.
user
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
"head12345"
],
[
"chapter2"
])
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
]
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
]
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
,
"problem3_2"
])
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
,
"problem3_2"
])
...
@@ -1625,10 +1642,11 @@ class TestPublish(SplitModuleTest):
...
@@ -1625,10 +1642,11 @@ class TestPublish(SplitModuleTest):
"""
"""
dest_cursor
=
0
dest_cursor
=
0
for
child
in
source_children
:
for
child
in
source_children
:
if
child
in
unexpected
:
child
=
child
.
version_agnostic
()
self
.
assertNotIn
(
child
,
dest_children
)
if
child
.
block_id
in
unexpected
:
self
.
assertNotIn
(
child
.
block_id
,
[
dest
.
block_id
for
dest
in
dest_children
])
else
:
else
:
self
.
assertEqual
(
child
,
dest_children
[
dest_cursor
]
)
self
.
assertEqual
(
child
.
block_id
,
dest_children
[
dest_cursor
]
.
block_id
)
dest_cursor
+=
1
dest_cursor
+=
1
self
.
assertEqual
(
dest_cursor
,
len
(
dest_children
))
self
.
assertEqual
(
dest_cursor
,
len
(
dest_children
))
...
...
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