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
d310ed9f
Commit
d310ed9f
authored
Sep 13, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixup! block_cache fixes.
parent
d5d7d654
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
126 additions
and
36 deletions
+126
-36
lms/envs/test.py
+8
-1
openedx/core/lib/block_cache/block_structure.py
+4
-0
openedx/core/lib/block_cache/graph_traversals.py
+23
-22
openedx/core/lib/block_cache/tests/test_block_cache.py
+36
-11
openedx/core/lib/block_cache/tests/test_graph_traversals.py
+50
-1
openedx/core/lib/block_cache/tests/test_utils.py
+5
-1
No files found.
lms/envs/test.py
View file @
d310ed9f
...
...
@@ -219,8 +219,15 @@ CACHES = {
'course_structure_cache'
:
{
'BACKEND'
:
'django.core.cache.backends.dummy.DummyCache'
,
},
'block_cache'
:
{
'BACKEND'
:
'django.core.cache.backends.locmem.LocMemCache'
,
'LOCATION'
:
os
.
path
.
join
(
tempfile
.
gettempdir
(),
'block_cache'
),
'KEY_FUNCTION'
:
'util.memcache.safe_key'
,
},
'lms.course_blocks'
:
{
'BACKEND'
:
'django.core.cache.backends.dummy.DummyCache'
,
'BACKEND'
:
'django.core.cache.backends.locmem.LocMemCache'
,
'LOCATION'
:
os
.
path
.
join
(
tempfile
.
gettempdir
(),
'course_blocks'
),
'KEY_FUNCTION'
:
'util.memcache.safe_key'
,
},
}
...
...
openedx/core/lib/block_cache/block_structure.py
View file @
d310ed9f
...
...
@@ -204,11 +204,15 @@ class BlockStructureFactory(object):
@classmethod
def
create_from_modulestore
(
cls
,
root_block_key
,
modulestore
):
block_structure
=
BlockStructureCollectedData
(
root_block_key
)
blocks_visited
=
set
()
def
build_block_structure
(
xblock
):
"""
Helper function to recursively walk block structure
"""
if
xblock
.
location
in
blocks_visited
:
return
blocks_visited
.
add
(
xblock
.
location
)
block_structure
.
add_xblock
(
xblock
)
for
child
in
xblock
.
get_children
():
block_structure
.
add_relation
(
xblock
.
location
,
child
.
location
)
...
...
openedx/core/lib/block_cache/graph_traversals.py
View file @
d310ed9f
...
...
@@ -52,28 +52,29 @@ def _traverse_generic(
if
not
all_parents_visited
or
(
not
yield_descendants_of_unyielded
and
not
any_parent_yielded
):
continue
# Add its unvisited children to the stack in reverse order so that
# they are popped off in their original order.
# It's important that we visit the children even if the parent isn't yielded
# in case a child has multiple parents and this is its last parent.
unvisited_children
=
get_children
(
curr_node
)
# If we're not doing a topological traversal, check whether the child has been visited.
if
not
get_parents
:
unvisited_children
=
list
(
child
for
child
in
unvisited_children
if
child
not
in
yield_results
)
unvisited_children
.
reverse
()
stack
.
extend
(
unvisited_children
)
# Return the result if it satisfies the predicate.
# Keep track of the result so we know whether to yield its children.
should_yield_node
=
predicate
(
curr_node
)
yield_results
[
curr_node
]
=
should_yield_node
if
should_yield_node
:
yield
get_result
(
curr_node
)
if
curr_node
not
in
yield_results
:
# Add its unvisited children to the stack in reverse order so that
# they are popped off in their original order.
# It's important that we visit the children even if the parent isn't yielded
# in case a child has multiple parents and this is its last parent.
unvisited_children
=
list
(
get_children
(
curr_node
))
# If we're not doing a topological traversal, check whether the child has been visited.
if
not
get_parents
:
unvisited_children
=
list
(
child
for
child
in
unvisited_children
if
child
not
in
yield_results
)
unvisited_children
.
reverse
()
stack
.
extend
(
unvisited_children
)
# Return the result if it satisfies the predicate.
# Keep track of the result so we know whether to yield its children.
should_yield_node
=
predicate
(
curr_node
)
yield_results
[
curr_node
]
=
should_yield_node
if
should_yield_node
:
yield
get_result
(
curr_node
)
def
traverse_topologically
(
start_node
,
get_parents
,
get_children
,
**
kwargs
):
...
...
openedx/core/lib/block_cache/tests/test_block_cache.py
View file @
d310ed9f
...
...
@@ -2,13 +2,16 @@
Tests for block_cache.py
"""
from
mock
import
patch
from
django.core.cache
import
get_cache
from
mock
import
patch
,
DEFAULT
from
unittest
import
TestCase
from
.test_utils
import
(
MockModulestoreFactory
,
MockCache
,
MockUserInfo
,
MockTransformer
,
ChildrenMapTestMixin
)
from
..block_cache
import
get_blocks
@patch
(
'openedx.core.lib.block_cache.transformer.BlockStructureTransformers.get_available_plugins'
)
class
TestBlockCache
(
TestCase
,
ChildrenMapTestMixin
):
class
TestTransformer1
(
MockTransformer
):
...
...
@@ -43,18 +46,40 @@ class TestBlockCache(TestCase, ChildrenMapTestMixin):
get_result
=
lambda
block_key
:
assert_collected_value
(
block_key
)
))
@patch
(
'openedx.core.lib.block_cache.transformer.BlockStructureTransformers.get_available_plugins'
)
def
setUp
(
self
):
super
(
TestBlockCache
,
self
)
.
setUp
()
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
user_info
=
MockUserInfo
()
self
.
mock_cache
=
MockCache
()
self
.
modulestore
=
MockModulestoreFactory
.
create
(
self
.
children_map
)
self
.
transformers
=
[
self
.
TestTransformer1
()]
def
test_get_blocks
(
self
,
mock_available_transforms
):
children_map
=
self
.
SIMPLE_CHILDREN_MAP
cache
=
MockCache
()
user_info
=
MockUserInfo
()
modulestore
=
MockModulestoreFactory
.
create
(
children_map
)
transformers
=
[
self
.
TestTransformer1
()]
mock_available_transforms
.
return_value
=
{
transformer
.
name
():
transformer
for
transformer
in
self
.
transformers
}
block_structure
=
get_blocks
(
self
.
mock_cache
,
self
.
modulestore
,
self
.
user_info
,
root_block_key
=
0
,
transformers
=
self
.
transformers
)
self
.
assert_block_structure
(
block_structure
,
self
.
children_map
)
def
test_unregistered_transformers
(
self
,
mock_available_transforms
):
mock_available_transforms
.
return_value
=
{}
with
self
.
assertRaisesRegexp
(
Exception
,
"requested transformers are not registered"
):
get_blocks
(
cache
,
modulestore
,
user_info
,
root_block_key
=
0
,
transformers
=
transformers
)
get_blocks
(
self
.
mock_cache
,
self
.
modulestore
,
self
.
user_info
,
root_block_key
=
0
,
transformers
=
self
.
transformers
)
def
test_block_caching
(
self
,
mock_available_transforms
):
mock_available_transforms
.
return_value
=
{
transformer
.
name
():
transformer
for
transformer
in
self
.
transformers
}
cache
=
get_cache
(
'block_cache'
)
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
.
assert_block_structure
(
block_structure
,
children_map
)
for
iteration
in
range
(
2
):
self
.
modulestore
.
get_items_call_count
=
0
block_structure
=
get_blocks
(
cache
,
self
.
modulestore
,
self
.
user_info
,
root_block_key
=
0
,
transformers
=
self
.
transformers
)
self
.
assert_block_structure
(
block_structure
,
self
.
children_map
)
if
iteration
==
0
:
self
.
assertTrue
(
self
.
modulestore
.
get_items_call_count
>
0
)
# else: TODO - debug issue with pickling
# self.assertEquals(self.modulestore.get_items_call_count, 0)
openedx/core/lib/block_cache/tests/test_graph_traversals.py
View file @
d310ed9f
...
...
@@ -21,7 +21,9 @@ class GraphTraversalsTestCase(TestCase):
"""
...
"""
# b1
# a1 a2
# | |
# b1 b2
# / \
# c1 c2
# / \ \
...
...
@@ -126,3 +128,50 @@ class GraphTraversalsTestCase(TestCase):
)),
[
'c2'
]
)
def
test_topological_complex
(
self
):
"""
Test a more complex DAG
"""
# root
# / | \
# / | \
# A B C
# / \ / | \ | \
# / \ / | \ | \
# D E F G H I
# / \ \ |
# / \ \ |
# J K \ L
# / | \ / \
# / | \ / \
# M N O P
graph
=
{
'root'
:
[
'A'
,
'B'
,
'C'
,
'E'
,
'F'
,
'K'
,
'O'
],
# has additional links than what is drawn above
'A'
:
[
'D'
,
'E'
],
'B'
:
[
'E'
,
'F'
,
'G'
],
'C'
:
[
'H'
,
'I'
],
'D'
:
[],
'E'
:
[],
'F'
:
[
'J'
,
'K'
],
'G'
:
[
'O'
],
'H'
:
[
'L'
],
'I'
:
[],
'J'
:
[],
'K'
:
[
'M'
,
'N'
],
'L'
:
[
'O'
,
'P'
],
'M'
:
[],
'N'
:
[],
'O'
:
[],
'P'
:
[],
}
graph_parents
=
self
.
get_parent_map
(
graph
)
for
_
in
range
(
2
):
# should get the same result twice
self
.
assertEqual
(
list
(
traverse_topologically
(
start_node
=
'root'
,
get_children
=
(
lambda
node
:
graph
[
node
]),
get_parents
=
(
lambda
node
:
graph_parents
[
node
]),
)),
[
'root'
,
'A'
,
'D'
,
'B'
,
'E'
,
'F'
,
'J'
,
'K'
,
'M'
,
'N'
,
'G'
,
'C'
,
'H'
,
'L'
,
'O'
,
'P'
,
'I'
],
)
openedx/core/lib/block_cache/tests/test_utils.py
View file @
d310ed9f
...
...
@@ -24,11 +24,15 @@ class MockXBlock(object):
class
MockModulestore
(
object
):
def
__init__
(
self
):
self
.
get_items_call_count
=
0
def
set_blocks
(
self
,
blocks
):
self
.
blocks
=
blocks
def
get_item
(
self
,
block_key
,
depth
=
None
):
return
self
.
blocks
.
get
(
block_key
)
self
.
get_items_call_count
+=
1
return
self
.
blocks
.
get
(
block_key
)
class
MockCache
(
object
):
...
...
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