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
2d64c54c
Commit
2d64c54c
authored
Sep 11, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixup! SplitTestTransformer skip split_test module.
parent
7a3b4104
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
195 additions
and
123 deletions
+195
-123
lms/djangoapps/course_blocks/transformers/helpers.py
+0
-30
lms/djangoapps/course_blocks/transformers/split_test.py
+4
-1
lms/djangoapps/course_blocks/transformers/tests/test_split_test.py
+4
-7
lms/djangoapps/course_blocks/transformers/user_partitions.py
+27
-1
openedx/core/lib/block_cache/block_structure.py
+14
-7
openedx/core/lib/block_cache/tests/test_block_cache.py
+4
-4
openedx/core/lib/block_cache/tests/test_block_structure.py
+81
-59
openedx/core/lib/block_cache/tests/test_utils.py
+61
-14
No files found.
lms/djangoapps/course_blocks/transformers/helpers.py
deleted
100644 → 0
View file @
7a3b4104
"""
Transformers helpers functions.
"""
def
get_user_partition_groups
(
course_key
,
user_partitions
,
user
):
"""
Collect group ID for each partition in this course for this user.
Arguments:
course_key (CourseKey)
user_partitions (list[UserPartition])
user (User)
Returns:
dict[int: Group]: Mapping from user partitions to the group to which
the user belongs in each partition. If the user isn't in a group
for a particular partition, then that partition's ID will not be
in the dict.
"""
partition_groups
=
{}
for
partition
in
user_partitions
:
group
=
partition
.
scheme
.
get_group_for_user
(
course_key
,
user
,
partition
,
)
if
group
is
not
None
:
partition_groups
[
partition
.
id
]
=
group
return
partition_groups
lms/djangoapps/course_blocks/transformers/split_test.py
View file @
2d64c54c
...
...
@@ -56,4 +56,7 @@ class SplitTestTransformer(BlockStructureTransformer):
user_info (object)
block_structure (BlockStructureCollectedData)
"""
pass
block_structure
.
remove_block_if
(
lambda
block_key
:
block_key
.
block_type
==
'split_test'
,
keep_descendants
=
True
,
)
lms/djangoapps/course_blocks/transformers/tests/test_split_test.py
View file @
2d64c54c
...
...
@@ -5,12 +5,9 @@ from openedx.core.djangoapps.user_api.partition_schemes import RandomUserPartiti
from
student.tests.factories
import
CourseEnrollmentFactory
from
xmodule.partitions.partitions
import
Group
,
UserPartition
from
course_blocks.transformers.split_test
import
SplitTestTransformer
from
course_blocks.transformers.user_partitions
import
UserPartitionTransformer
from
course_blocks.api
import
get_course_blocks
from
lms.djangoapps.course_blocks.transformers.tests.test_helpers
import
CourseStructureTestCase
from
course_blocks.transformers.helpers
import
get_user_partition_groups
from
...api
import
get_course_blocks
from
..user_partitions
import
UserPartitionTransformer
,
get_user_partition_groups
from
.test_helpers
import
CourseStructureTestCase
class
SplitTestTransformerTestCase
(
CourseStructureTestCase
):
...
...
@@ -132,7 +129,7 @@ class SplitTestTransformerTestCase(CourseStructureTestCase):
self
.
assertEquals
(
len
(
user_groups
),
1
)
group
=
user_groups
[
self
.
split_test_user_partition_id
]
expected_blocks
=
[
'course'
,
'chapter1'
,
'lesson1'
,
'vertical1'
,
'split_test1'
]
expected_blocks
=
[
'course'
,
'chapter1'
,
'lesson1'
,
'vertical1'
]
if
group
.
id
==
3
:
expected_blocks
+=
[
'vertical2'
,
'html1'
]
else
:
...
...
lms/djangoapps/course_blocks/transformers/user_partitions.py
View file @
2d64c54c
...
...
@@ -3,7 +3,6 @@ User Partitions Transformer
"""
from
openedx.core.lib.block_cache.transformer
import
BlockStructureTransformer
from
.helpers
import
get_user_partition_groups
from
.split_test
import
SplitTestTransformer
...
...
@@ -108,6 +107,33 @@ class MergedGroupAccess(object):
return
True
def
get_user_partition_groups
(
course_key
,
user_partitions
,
user
):
"""
Collect group ID for each partition in this course for this user.
Arguments:
course_key (CourseKey)
user_partitions (list[UserPartition])
user (User)
Returns:
dict[int: Group]: Mapping from user partitions to the group to which
the user belongs in each partition. If the user isn't in a group
for a particular partition, then that partition's ID will not be
in the dict.
"""
partition_groups
=
{}
for
partition
in
user_partitions
:
group
=
partition
.
scheme
.
get_group_for_user
(
course_key
,
user
,
partition
,
)
if
group
is
not
None
:
partition_groups
[
partition
.
id
]
=
group
return
partition_groups
class
UserPartitionTransformer
(
BlockStructureTransformer
):
"""
...
...
...
openedx/core/lib/block_cache/block_structure.py
View file @
2d64c54c
...
...
@@ -34,7 +34,7 @@ class BlockStructure(object):
self
.
_add_relation
(
self
.
_block_relations
,
parent_key
,
child_key
)
def
get_parents
(
self
,
usage_key
):
return
self
.
_block_relations
.
get
(
usage_key
)
.
parents
if
self
.
has_block
(
usage_key
)
else
[]
return
self
.
_block_relations
[
usage_key
]
.
parents
if
self
.
has_block
(
usage_key
)
else
[]
def
get_children
(
self
,
usage_key
):
return
self
.
_block_relations
[
usage_key
]
.
children
if
self
.
has_block
(
usage_key
)
else
[]
...
...
@@ -134,23 +134,30 @@ class BlockStructureBlockData(BlockStructure):
def
remove_transformer_block_data
(
self
,
usage_key
,
transformer
,
key
):
self
.
_block_data_map
[
usage_key
]
.
_transformer_data
.
get
(
transformer
.
name
(),
{})
.
pop
(
key
,
None
)
def
remove_block
(
self
,
usage_key
):
def
remove_block
(
self
,
usage_key
,
keep_descendants
):
children
=
self
.
_block_relations
[
usage_key
]
.
children
parents
=
self
.
_block_relations
[
usage_key
]
.
parents
# Remove block from its children.
for
child
in
self
.
_block_relations
[
usage_key
]
.
children
:
for
child
in
children
:
self
.
_block_relations
[
child
]
.
parents
.
remove
(
usage_key
)
# Remove block from its parents.
for
parent
_key
in
self
.
_block_relations
[
usage_key
]
.
parents
:
self
.
_block_relations
[
parent
_key
]
.
children
.
remove
(
usage_key
)
for
parent
in
parents
:
self
.
_block_relations
[
parent
]
.
children
.
remove
(
usage_key
)
# Remove block.
self
.
_block_relations
.
pop
(
usage_key
,
None
)
self
.
_block_data_map
.
pop
(
usage_key
,
None
)
def
remove_block_if
(
self
,
removal_condition
,
**
kwargs
):
# Recreate the graph connections if descendants are to be kept.
if
keep_descendants
:
[
self
.
add_relation
(
parent
,
child
)
for
child
in
children
for
parent
in
parents
]
def
remove_block_if
(
self
,
removal_condition
,
keep_descendants
=
False
,
**
kwargs
):
def
predicate
(
block_key
):
if
removal_condition
(
block_key
):
self
.
remove_block
(
block_key
)
self
.
remove_block
(
block_key
,
keep_descendants
)
return
False
return
True
list
(
self
.
topological_traversal
(
predicate
=
predicate
,
**
kwargs
))
...
...
openedx/core/lib/block_cache/tests/test_block_cache.py
View file @
2d64c54c
...
...
@@ -5,11 +5,11 @@ Tests for block_cache.py
from
mock
import
patch
from
unittest
import
TestCase
from
.test_utils
import
(
MockModulestoreFactory
,
MockCache
,
MockUserInfo
,
MockTransformer
,
SIMPLE_CHILDREN_MAP
,
BlockStructure
TestMixin
MockModulestoreFactory
,
MockCache
,
MockUserInfo
,
MockTransformer
,
ChildrenMap
TestMixin
)
from
..block_cache
import
get_blocks
class
TestBlockCache
(
TestCase
,
BlockStructure
TestMixin
):
class
TestBlockCache
(
TestCase
,
ChildrenMap
TestMixin
):
class
TestTransformer1
(
MockTransformer
):
@classmethod
...
...
@@ -45,7 +45,7 @@ class TestBlockCache(TestCase, BlockStructureTestMixin):
@patch
(
'openedx.core.lib.block_cache.transformer.BlockStructureTransformers.get_available_plugins'
)
def
test_get_blocks
(
self
,
mock_available_transforms
):
children_map
=
SIMPLE_CHILDREN_MAP
children_map
=
self
.
SIMPLE_CHILDREN_MAP
cache
=
MockCache
()
user_info
=
MockUserInfo
()
modulestore
=
MockModulestoreFactory
.
create
(
children_map
)
...
...
@@ -57,4 +57,4 @@ class TestBlockCache(TestCase, BlockStructureTestMixin):
mock_available_transforms
.
return_value
=
{
transformer
.
name
():
transformer
for
transformer
in
transformers
}
block_structure
=
get_blocks
(
cache
,
modulestore
,
user_info
,
root_block_key
=
0
,
transformers
=
transformers
)
self
.
verify
_block_structure
(
block_structure
,
children_map
)
self
.
assert
_block_structure
(
block_structure
,
children_map
)
openedx/core/lib/block_cache/tests/test_block_structure.py
View file @
2d64c54c
...
...
@@ -2,62 +2,36 @@
Tests for block_structure.py
"""
from
collections
import
namedtuple
from
copy
import
deepcopy
import
ddt
import
itertools
from
mock
import
patch
from
unittest
import
TestCase
from
..block_structure
import
(
BlockStructure
,
BlockStructureCollectedData
,
BlockStructureBlockData
,
BlockStructureFactory
)
from
..graph_traversals
import
traverse_post_order
from
..transformer
import
BlockStructureTransformer
,
BlockStructureTransformers
from
.test_utils
import
(
MockCache
,
MockXBlock
,
MockModulestoreFactory
,
MockTransformer
,
SIMPLE_CHILDREN_MAP
,
BlockStructureTestMixin
MockCache
,
MockXBlock
,
MockModulestoreFactory
,
MockTransformer
,
ChildrenMapTestMixin
)
@ddt.ddt
class
TestBlockStructure
(
TestCase
):
class
TestBlockStructure
(
TestCase
,
ChildrenMapTestMixin
):
"""
Tests for BlockStructure
"""
def
get_parents_map
(
self
,
children_map
):
parent_map
=
[[]
for
node
in
children_map
]
for
parent
,
children
in
enumerate
(
children_map
):
for
child
in
children
:
parent_map
[
child
]
.
append
(
parent
)
return
parent_map
@ddt.data
(
[],
# 0
# / \
# 1 2
# / \
# 3 4
SIMPLE_CHILDREN_MAP
,
# 0
# /
# 1
# /
# 2
# /
# 3
[[
1
],
[
2
],
[
3
],
[]],
# 0
# / \
# 1 2
# \ /
# 3
[[
1
,
2
],
[
3
],
[
3
],
[]],
ChildrenMapTestMixin
.
SIMPLE_CHILDREN_MAP
,
ChildrenMapTestMixin
.
LINEAR_CHILDREN_MAP
,
ChildrenMapTestMixin
.
DAG_CHILDREN_MAP
,
)
def
test_relations
(
self
,
children_map
):
# create block structure
block_structure
=
BlockStructure
(
root_block_key
=
0
)
# add_relation
for
parent
,
children
in
enumerate
(
children_map
):
for
child
in
children
:
block_structure
.
add_relation
(
parent
,
child
)
block_structure
=
self
.
create_block_structure
(
BlockStructure
,
children_map
)
# get_children
for
parent
,
children
in
enumerate
(
children_map
):
...
...
@@ -73,7 +47,8 @@ class TestBlockStructure(TestCase):
self
.
assertFalse
(
block_structure
.
has_block
(
len
(
children_map
)
+
1
))
class
TestBlockStructureData
(
TestCase
):
@ddt.ddt
class
TestBlockStructureData
(
TestCase
,
ChildrenMapTestMixin
):
"""
Tests for BlockStructureBlockData and BlockStructureCollectedData
"""
...
...
@@ -176,41 +151,88 @@ class TestBlockStructureData(TestCase):
block
.
field_map
.
get
(
field
),
)
def
test_remove_block
(
self
):
block_structure
=
BlockStructureBlockData
(
root_block_key
=
0
)
for
parent
,
children
in
enumerate
(
SIMPLE_CHILDREN_MAP
):
for
child
in
children
:
block_structure
.
add_relation
(
parent
,
child
)
self
.
assertTrue
(
block_structure
.
has_block
(
1
))
self
.
assertTrue
(
1
in
block_structure
.
get_children
(
0
))
block_structure
.
remove_block
(
1
)
self
.
assertFalse
(
block_structure
.
has_block
(
1
))
self
.
assertFalse
(
1
in
block_structure
.
get_children
(
0
))
@ddt.data
(
*
itertools
.
product
(
[
True
,
False
],
range
(
7
),
[
# ChildrenMapTestMixin.SIMPLE_CHILDREN_MAP,
ChildrenMapTestMixin
.
LINEAR_CHILDREN_MAP
,
# ChildrenMapTestMixin.DAG_CHILDREN_MAP,
],
)
)
@ddt.unpack
def
test_remove_block
(
self
,
keep_descendants
,
block_to_remove
,
children_map
):
### skip test if invalid
if
(
(
block_to_remove
>=
len
(
children_map
))
or
(
keep_descendants
and
block_to_remove
==
0
)
):
return
### create structure
block_structure
=
self
.
create_block_structure
(
BlockStructureBlockData
,
children_map
)
parents_map
=
self
.
get_parents_map
(
children_map
)
### verify blocks pre-exist
self
.
assert_block_structure
(
block_structure
,
children_map
)
### remove block
block_structure
.
remove_block
(
block_to_remove
,
keep_descendants
)
missing_blocks
=
[
block_to_remove
]
### compute and verify updated children_map
removed_children_map
=
deepcopy
(
children_map
)
removed_children_map
[
block_to_remove
]
=
[]
[
removed_children_map
[
parent
]
.
remove
(
block_to_remove
)
for
parent
in
parents_map
[
block_to_remove
]]
if
keep_descendants
:
# update the graph connecting the old parents to the old children
[
removed_children_map
[
parent
]
.
append
(
child
)
for
child
in
children_map
[
block_to_remove
]
for
parent
in
parents_map
[
block_to_remove
]
]
self
.
assert_block_structure
(
block_structure
,
removed_children_map
,
missing_blocks
)
### prune the structure
block_structure
.
prune
()
self
.
assertTrue
(
block_structure
.
has_block
(
3
))
self
.
assertTrue
(
block_structure
.
has_block
(
4
)
)
### compute and verify updated children_map
pruned_children_map
=
deepcopy
(
removed_children_map
)
block_structure
.
prune
()
if
not
keep_descendants
:
def
update_descendant
(
block
):
"""
add descendant to missing blocks and empty its children
"""
missing_blocks
.
append
(
block
)
pruned_children_map
[
block
]
=
[]
self
.
assertFalse
(
block_structure
.
has_block
(
3
))
self
.
assertFalse
(
block_structure
.
has_block
(
4
))
# update all descendants
for
child
in
children_map
[
block_to_remove
]:
list
(
traverse_post_order
(
child
,
get_children
=
lambda
block
:
pruned_children_map
[
block
],
get_result
=
update_descendant
,
))
self
.
assert_block_structure
(
block_structure
,
pruned_children_map
,
missing_blocks
)
class
TestBlockStructureFactory
(
TestCase
,
BlockStructure
TestMixin
):
class
TestBlockStructureFactory
(
TestCase
,
ChildrenMap
TestMixin
):
"""
Tests for BlockStructureFactory
"""
def
test_factory_methods
(
self
):
children_map
=
SIMPLE_CHILDREN_MAP
children_map
=
self
.
SIMPLE_CHILDREN_MAP
modulestore
=
MockModulestoreFactory
.
create
(
children_map
)
cache
=
MockCache
()
# test create from modulestore
block_structure
=
BlockStructureFactory
.
create_from_modulestore
(
root_block_key
=
0
,
modulestore
=
modulestore
)
self
.
verify
_block_structure
(
block_structure
,
children_map
)
self
.
assert
_block_structure
(
block_structure
,
children_map
)
# test not in cache
self
.
assertIsNone
(
BlockStructureFactory
.
create_from_cache
(
root_block_key
=
0
,
cache
=
cache
))
...
...
@@ -232,7 +254,7 @@ class TestBlockStructureFactory(TestCase, BlockStructureTestMixin):
# test re-create from cache
from_cache_block_structure
=
BlockStructureFactory
.
create_from_cache
(
root_block_key
=
0
,
cache
=
cache
)
self
.
assertIsNotNone
(
from_cache_block_structure
)
self
.
verify
_block_structure
(
from_cache_block_structure
,
children_map
)
self
.
assert
_block_structure
(
from_cache_block_structure
,
children_map
)
# test remove from cache
BlockStructureFactory
.
remove_from_cache
(
root_block_key
=
0
,
cache
=
cache
)
...
...
openedx/core/lib/block_cache/tests/test_utils.py
View file @
2d64c54c
...
...
@@ -74,21 +74,68 @@ class MockTransformer(BlockStructureTransformer):
pass
# 0
# / \
# 1 2
# / \
# 3 4
SIMPLE_CHILDREN_MAP
=
[[
1
,
2
],
[
3
,
4
],
[],
[],
[]]
class
ChildrenMapTestMixin
(
object
):
# 0
# / \
# 1 2
# / \
# 3 4
SIMPLE_CHILDREN_MAP
=
[[
1
,
2
],
[
3
,
4
],
[],
[],
[]]
# 0
# /
# 1
# /
# 2
# /
# 3
LINEAR_CHILDREN_MAP
=
[[
1
],
[
2
],
[
3
],
[]]
# 0
# / \
# 1 2
# \ / \
# 3 4
# / \
# 5 6
DAG_CHILDREN_MAP
=
[[
1
,
2
],
[
3
],
[
3
,
4
],
[
5
,
6
],
[],
[],
[]]
def
create_block_structure
(
self
,
block_structure_cls
,
children_map
):
# create block structure
block_structure
=
block_structure_cls
(
root_block_key
=
0
)
# add_relation
for
parent
,
children
in
enumerate
(
children_map
):
for
child
in
children
:
block_structure
.
add_relation
(
parent
,
child
)
return
block_structure
def
get_parents_map
(
self
,
children_map
):
parent_map
=
[[]
for
_
in
children_map
]
for
parent
,
children
in
enumerate
(
children_map
):
for
child
in
children
:
parent_map
[
child
]
.
append
(
parent
)
return
parent_map
def
assert_block_structure
(
self
,
block_structure
,
children_map
,
missing_blocks
=
None
):
if
not
missing_blocks
:
missing_blocks
=
[]
class
BlockStructureTestMixin
(
object
):
def
verify_block_structure
(
self
,
block_structure
,
children_map
):
for
block_key
,
children
in
enumerate
(
children_map
):
self
.
assertTrue
(
block_structure
.
has_block
(
block_key
)
)
self
.
assertEquals
(
set
(
block_structure
.
get_children
(
block_key
)
),
set
(
children
)
,
block_structure
.
has_block
(
block_key
),
block_key
not
in
missing_blocks
,
)
if
block_key
not
in
missing_blocks
:
self
.
assertEquals
(
set
(
block_structure
.
get_children
(
block_key
)),
set
(
children
),
)
parents_map
=
self
.
get_parents_map
(
children_map
)
for
block_key
,
parents
in
enumerate
(
parents_map
):
if
block_key
not
in
missing_blocks
:
self
.
assertEquals
(
set
(
block_structure
.
get_parents
(
block_key
)),
set
(
parents
),
)
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