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
1ee2c27f
Commit
1ee2c27f
authored
Feb 26, 2017
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Storage-backed versioned Block Structures: Manager and Store
parent
77a29242
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
485 additions
and
250 deletions
+485
-250
lms/djangoapps/course_blocks/management/commands/generate_course_blocks.py
+2
-2
openedx/core/djangoapps/content/block_structure/api.py
+1
-1
openedx/core/djangoapps/content/block_structure/tests/helpers.py
+7
-3
openedx/core/lib/block_structure/cache.py
+0
-133
openedx/core/lib/block_structure/exceptions.py
+4
-1
openedx/core/lib/block_structure/factory.py
+6
-10
openedx/core/lib/block_structure/manager.py
+24
-12
openedx/core/lib/block_structure/store.py
+258
-0
openedx/core/lib/block_structure/tests/helpers.py
+44
-12
openedx/core/lib/block_structure/tests/test_cache.py
+0
-56
openedx/core/lib/block_structure/tests/test_factory.py
+9
-9
openedx/core/lib/block_structure/tests/test_manager.py
+37
-11
openedx/core/lib/block_structure/tests/test_store.py
+93
-0
No files found.
lms/djangoapps/course_blocks/management/commands/generate_course_blocks.py
View file @
1ee2c27f
...
@@ -8,7 +8,7 @@ from xmodule.modulestore.django import modulestore
...
@@ -8,7 +8,7 @@ from xmodule.modulestore.django import modulestore
import
openedx.core.djangoapps.content.block_structure.api
as
api
import
openedx.core.djangoapps.content.block_structure.api
as
api
import
openedx.core.djangoapps.content.block_structure.tasks
as
tasks
import
openedx.core.djangoapps.content.block_structure.tasks
as
tasks
import
openedx.core.lib.block_structure.
cache
as
cach
e
import
openedx.core.lib.block_structure.
store
as
stor
e
from
openedx.core.lib.command_utils
import
(
from
openedx.core.lib.command_utils
import
(
get_mutually_exclusive_required_option
,
get_mutually_exclusive_required_option
,
validate_dependent_option
,
validate_dependent_option
,
...
@@ -113,7 +113,7 @@ class Command(BaseCommand):
...
@@ -113,7 +113,7 @@ class Command(BaseCommand):
cache_log_level
=
logging
.
INFO
cache_log_level
=
logging
.
INFO
log
.
setLevel
(
log_level
)
log
.
setLevel
(
log_level
)
cach
e
.
logger
.
setLevel
(
cache_log_level
)
stor
e
.
logger
.
setLevel
(
cache_log_level
)
def
_generate_course_blocks
(
self
,
options
,
course_keys
):
def
_generate_course_blocks
(
self
,
options
,
course_keys
):
"""
"""
...
...
openedx/core/djangoapps/content/block_structure/api.py
View file @
1ee2c27f
...
@@ -25,7 +25,7 @@ def update_course_in_cache(course_key):
...
@@ -25,7 +25,7 @@ def update_course_in_cache(course_key):
block_structure.updated_collected function that updates the block
block_structure.updated_collected function that updates the block
structure in the cache for the given course_key.
structure in the cache for the given course_key.
"""
"""
return
get_block_structure_manager
(
course_key
)
.
update_collected
()
return
get_block_structure_manager
(
course_key
)
.
update_collected
_if_needed
()
def
clear_course_from_cache
(
course_key
):
def
clear_course_from_cache
(
course_key
):
...
...
openedx/core/djangoapps/content/block_structure/tests/helpers.py
View file @
1ee2c27f
"""
"""
Helpers for Course Blocks tests.
Helpers for Course Blocks tests.
"""
"""
from
openedx.core.lib.block_structure.cache
import
BlockStructureCache
from
openedx.core.djangolib.testing.waffle_utils
import
override_switch
from
openedx.core.djangolib.testing.waffle_utils
import
override_switch
from
openedx.core.lib.block_structure.exceptions
import
BlockStructureNotFound
from
openedx.core.lib.block_structure.store
import
BlockStructureStore
from
..api
import
get_cache
from
..api
import
get_cache
from
..config
import
_bs_waffle_switch_name
from
..config
import
_bs_waffle_switch_name
...
@@ -14,7 +14,11 @@ def is_course_in_block_structure_cache(course_key, store):
...
@@ -14,7 +14,11 @@ def is_course_in_block_structure_cache(course_key, store):
Returns whether the given course is in the Block Structure cache.
Returns whether the given course is in the Block Structure cache.
"""
"""
course_usage_key
=
store
.
make_course_usage_key
(
course_key
)
course_usage_key
=
store
.
make_course_usage_key
(
course_key
)
return
BlockStructureCache
(
get_cache
())
.
get
(
course_usage_key
)
is
not
None
try
:
BlockStructureStore
(
get_cache
())
.
get
(
course_usage_key
)
return
True
except
BlockStructureNotFound
:
return
False
class
override_config_setting
(
override_switch
):
# pylint:disable=invalid-name
class
override_config_setting
(
override_switch
):
# pylint:disable=invalid-name
...
...
openedx/core/lib/block_structure/cache.py
deleted
100644 → 0
View file @
77a29242
"""
Module for the Cache class for BlockStructure objects.
"""
# pylint: disable=protected-access
from
logging
import
getLogger
from
openedx.core.lib.cache_utils
import
zpickle
,
zunpickle
from
.block_structure
import
BlockStructureBlockData
from
.factory
import
BlockStructureFactory
logger
=
getLogger
(
__name__
)
# pylint: disable=C0103
class
BlockStructureCache
(
object
):
"""
Cache for BlockStructure objects.
"""
def
__init__
(
self
,
cache
):
"""
Arguments:
cache (django.core.cache.backends.base.BaseCache) - The
cache into which cacheable data of the block structure
is to be serialized.
"""
self
.
_cache
=
cache
def
add
(
self
,
block_structure
):
"""
Store a compressed and pickled serialization of the given
block structure into the given cache.
The key in the cache is 'root.key.<root_block_usage_key>'.
The data stored in the cache includes the structure's
block relations, transformer data, and block data.
Arguments:
block_structure (BlockStructure) - The block structure
that is to be serialized to the given cache.
"""
data_to_cache
=
(
block_structure
.
_block_relations
,
block_structure
.
transformer_data
,
block_structure
.
_block_data_map
,
)
zp_data_to_cache
=
zpickle
(
data_to_cache
)
# Set the timeout value for the cache to 1 day as a fail-safe
# in case the signal to invalidate the cache doesn't come through.
timeout_in_seconds
=
60
*
60
*
24
self
.
_cache
.
set
(
self
.
_encode_root_cache_key
(
block_structure
.
root_block_usage_key
),
zp_data_to_cache
,
timeout
=
timeout_in_seconds
,
)
logger
.
info
(
"Wrote BlockStructure
%
s to cache, size:
%
s"
,
block_structure
.
root_block_usage_key
,
len
(
zp_data_to_cache
),
)
def
get
(
self
,
root_block_usage_key
):
"""
Deserializes and returns the block structure starting at
root_block_usage_key from the given cache, if it's found in the cache.
The given root_block_usage_key must equate the root_block_usage_key
previously passed to serialize_to_cache.
Arguments:
root_block_usage_key (UsageKey) - The usage_key for the root
of the block structure that is to be deserialized from
the given cache.
Returns:
BlockStructure - The deserialized block structure starting
at root_block_usage_key, if found in the cache.
NoneType - If the root_block_usage_key is not found in the cache.
"""
# Find root_block_usage_key in the cache.
zp_data_from_cache
=
self
.
_cache
.
get
(
self
.
_encode_root_cache_key
(
root_block_usage_key
))
if
not
zp_data_from_cache
:
logger
.
info
(
"Did not find BlockStructure
%
r in the cache."
,
root_block_usage_key
,
)
return
None
else
:
logger
.
info
(
"Read BlockStructure
%
r from cache, size:
%
s"
,
root_block_usage_key
,
len
(
zp_data_from_cache
),
)
# Deserialize and construct the block structure.
block_relations
,
transformer_data
,
block_data_map
=
zunpickle
(
zp_data_from_cache
)
return
BlockStructureFactory
.
create_new
(
root_block_usage_key
,
block_relations
,
transformer_data
,
block_data_map
,
)
def
delete
(
self
,
root_block_usage_key
):
"""
Deletes the block structure for the given root_block_usage_key
from the given cache.
Arguments:
root_block_usage_key (UsageKey) - The usage_key for the root
of the block structure that is to be removed from
the cache.
"""
self
.
_cache
.
delete
(
self
.
_encode_root_cache_key
(
root_block_usage_key
))
logger
.
info
(
"Deleted BlockStructure
%
r from the cache."
,
root_block_usage_key
,
)
@classmethod
def
_encode_root_cache_key
(
cls
,
root_block_usage_key
):
"""
Returns the cache key to use for storing the block structure
for the given root_block_usage_key.
"""
return
"v{version}.root.key.{root_usage_key}"
.
format
(
version
=
unicode
(
BlockStructureBlockData
.
VERSION
),
root_usage_key
=
unicode
(
root_block_usage_key
),
)
openedx/core/lib/block_structure/exceptions.py
View file @
1ee2c27f
...
@@ -36,4 +36,7 @@ class BlockStructureNotFound(BlockStructureException):
...
@@ -36,4 +36,7 @@ class BlockStructureNotFound(BlockStructureException):
"""
"""
Exception for when a Block Structure is not found.
Exception for when a Block Structure is not found.
"""
"""
pass
def
__init__
(
self
,
root_block_usage_key
):
super
(
BlockStructureNotFound
,
self
)
.
__init__
(
'Block structure not found; data_usage_key: {}'
.
format
(
root_block_usage_key
)
)
openedx/core/lib/block_structure/factory.py
View file @
1ee2c27f
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
Module for factory class for BlockStructure objects.
Module for factory class for BlockStructure objects.
"""
"""
from
.block_structure
import
BlockStructureModulestoreData
,
BlockStructureBlockData
from
.block_structure
import
BlockStructureModulestoreData
,
BlockStructureBlockData
from
.exceptions
import
BlockStructureNotFound
class
BlockStructureFactory
(
object
):
class
BlockStructureFactory
(
object
):
...
@@ -59,10 +58,10 @@ class BlockStructureFactory(object):
...
@@ -59,10 +58,10 @@ class BlockStructureFactory(object):
return
block_structure
return
block_structure
@classmethod
@classmethod
def
create_from_
cache
(
cls
,
root_block_usage_key
,
block_structure_cach
e
):
def
create_from_
store
(
cls
,
root_block_usage_key
,
block_structure_stor
e
):
"""
"""
Deserializes and returns the block structure starting at
Deserializes and returns the block structure starting at
root_block_usage_key from the given
cache, if it's found in the cach
e.
root_block_usage_key from the given
store, if it's found in the stor
e.
The given root_block_usage_key must equate the root_block_usage_key
The given root_block_usage_key must equate the root_block_usage_key
previously passed to serialize_to_cache.
previously passed to serialize_to_cache.
...
@@ -72,8 +71,8 @@ class BlockStructureFactory(object):
...
@@ -72,8 +71,8 @@ class BlockStructureFactory(object):
of the block structure that is to be deserialized from
of the block structure that is to be deserialized from
the given cache.
the given cache.
block_structure_
cache (BlockStructureCach
e) - The
block_structure_
store (BlockStructureStor
e) - The
cach
e from which the block structure is to be
stor
e from which the block structure is to be
deserialized.
deserialized.
Returns:
Returns:
...
@@ -82,12 +81,9 @@ class BlockStructureFactory(object):
...
@@ -82,12 +81,9 @@ class BlockStructureFactory(object):
Raises:
Raises:
BlockStructureNotFound - If the root_block_usage_key is not found
BlockStructureNotFound - If the root_block_usage_key is not found
in the
cach
e.
in the
stor
e.
"""
"""
block_structure
=
block_structure_cache
.
get
(
root_block_usage_key
)
return
block_structure_store
.
get
(
root_block_usage_key
)
if
block_structure
is
None
:
raise
BlockStructureNotFound
(
'Block structure for {} not found in the cache.'
.
format
(
root_block_usage_key
))
return
block_structure
@classmethod
@classmethod
def
create_new
(
cls
,
root_block_usage_key
,
block_relations
,
transformer_data
,
block_data_map
):
def
create_new
(
cls
,
root_block_usage_key
,
block_relations
,
transformer_data
,
block_data_map
):
...
...
openedx/core/lib/block_structure/manager.py
View file @
1ee2c27f
...
@@ -4,9 +4,11 @@ BlockStructures.
...
@@ -4,9 +4,11 @@ BlockStructures.
"""
"""
from
contextlib
import
contextmanager
from
contextlib
import
contextmanager
from
.cache
import
BlockStructureCache
from
openedx.core.djangoapps.content.block_structure
import
config
from
.factory
import
BlockStructureFactory
from
.exceptions
import
UsageKeyNotInBlockStructure
,
TransformerDataIncompatible
,
BlockStructureNotFound
from
.exceptions
import
UsageKeyNotInBlockStructure
,
TransformerDataIncompatible
,
BlockStructureNotFound
from
.factory
import
BlockStructureFactory
from
.store
import
BlockStructureStore
from
.transformers
import
BlockStructureTransformers
from
.transformers
import
BlockStructureTransformers
...
@@ -31,7 +33,7 @@ class BlockStructureManager(object):
...
@@ -31,7 +33,7 @@ class BlockStructureManager(object):
"""
"""
self
.
root_block_usage_key
=
root_block_usage_key
self
.
root_block_usage_key
=
root_block_usage_key
self
.
modulestore
=
modulestore
self
.
modulestore
=
modulestore
self
.
block_structure_cache
=
BlockStructureCach
e
(
cache
)
self
.
store
=
BlockStructureStor
e
(
cache
)
def
get_transformed
(
self
,
transformers
,
starting_block_usage_key
=
None
,
collected_block_structure
=
None
):
def
get_transformed
(
self
,
transformers
,
starting_block_usage_key
=
None
,
collected_block_structure
=
None
):
"""
"""
...
@@ -90,22 +92,32 @@ class BlockStructureManager(object):
...
@@ -90,22 +92,32 @@ class BlockStructureManager(object):
from each registered transformer.
from each registered transformer.
"""
"""
try
:
try
:
block_structure
=
BlockStructureFactory
.
create_from_
cach
e
(
block_structure
=
BlockStructureFactory
.
create_from_
stor
e
(
self
.
root_block_usage_key
,
self
.
root_block_usage_key
,
self
.
block_structure_cache
self
.
store
,
)
)
BlockStructureTransformers
.
verify_versions
(
block_structure
)
BlockStructureTransformers
.
verify_versions
(
block_structure
)
except
(
BlockStructureNotFound
,
TransformerDataIncompatible
):
except
(
BlockStructureNotFound
,
TransformerDataIncompatible
):
block_structure
=
self
.
update_collected
()
if
config
.
is_enabled
(
config
.
RAISE_ERROR_WHEN_NOT_FOUND
):
raise
else
:
block_structure
=
self
.
_update_collected
()
return
block_structure
return
block_structure
def
update_collected
(
self
):
def
update_collected
_if_needed
(
self
):
"""
"""
Updates the collected Block Structure for the root_block_usage_key.
The store is updated with newly collected transformers data from
the modulestore, only if the data in the store is outdated.
"""
with
self
.
_bulk_operations
():
if
not
self
.
store
.
is_up_to_date
(
self
.
root_block_usage_key
,
self
.
modulestore
):
self
.
_update_collected
()
Details: The cache is updated by collecting transformers data from
def
_update_collected
(
self
):
"""
The store is updated with newly collected transformers data from
the modulestore.
the modulestore.
"""
"""
with
self
.
_bulk_operations
():
with
self
.
_bulk_operations
():
...
@@ -114,15 +126,15 @@ class BlockStructureManager(object):
...
@@ -114,15 +126,15 @@ class BlockStructureManager(object):
self
.
modulestore
,
self
.
modulestore
,
)
)
BlockStructureTransformers
.
collect
(
block_structure
)
BlockStructureTransformers
.
collect
(
block_structure
)
self
.
block_structure_cach
e
.
add
(
block_structure
)
self
.
stor
e
.
add
(
block_structure
)
return
block_structure
return
block_structure
def
clear
(
self
):
def
clear
(
self
):
"""
"""
Removes
cached
data for the block structure associated with the given
Removes data for the block structure associated with the given
root block key.
root block key.
"""
"""
self
.
block_structure_cach
e
.
delete
(
self
.
root_block_usage_key
)
self
.
stor
e
.
delete
(
self
.
root_block_usage_key
)
@contextmanager
@contextmanager
def
_bulk_operations
(
self
):
def
_bulk_operations
(
self
):
...
...
openedx/core/lib/block_structure/store.py
0 → 100644
View file @
1ee2c27f
"""
Module for the Storage of BlockStructure objects.
"""
# pylint: disable=protected-access
from
logging
import
getLogger
import
openedx.core.djangoapps.content.block_structure.config
as
config
from
openedx.core.djangoapps.content.block_structure.models
import
BlockStructureModel
from
openedx.core.lib.cache_utils
import
zpickle
,
zunpickle
from
.block_structure
import
BlockStructureBlockData
from
.exceptions
import
BlockStructureNotFound
from
.factory
import
BlockStructureFactory
from
.transformer_registry
import
TransformerRegistry
logger
=
getLogger
(
__name__
)
# pylint: disable=C0103
class
StubModel
(
object
):
"""
Stub model to use when storage backing is disabled.
By using this stub, we eliminate the need for extra
conditional statements in the code.
"""
def
__init__
(
self
,
root_block_usage_key
):
self
.
data_usage_key
=
root_block_usage_key
def
__unicode__
(
self
):
return
unicode
(
self
.
data_usage_key
)
def
delete
(
self
):
"""
Noop delete method.
"""
pass
class
BlockStructureStore
(
object
):
"""
Storage for BlockStructure objects.
"""
def
__init__
(
self
,
cache
):
"""
Arguments:
cache (django.core.cache.backends.base.BaseCache) - The
cache into which cacheable data of the block structure
is to be serialized.
"""
self
.
_cache
=
cache
def
add
(
self
,
block_structure
):
"""
Stores and caches a compressed and pickled serialization of
the given block structure.
The data stored includes the structure's
block relations, transformer data, and block data.
Arguments:
block_structure (BlockStructure) - The block structure
that is to be cached and stored.
"""
serialized_data
=
self
.
_serialize
(
block_structure
)
bs_model
=
self
.
_update_or_create_model
(
block_structure
,
serialized_data
)
self
.
_add_to_cache
(
serialized_data
,
bs_model
)
def
get
(
self
,
root_block_usage_key
):
"""
Deserializes and returns the block structure starting at
root_block_usage_key, if found in the cache or storage.
The given root_block_usage_key must equate the
root_block_usage_key previously passed to the `add` method.
Arguments:
root_block_usage_key (UsageKey) - The usage_key for the
root of the block structure that is to be retrieved
from the store.
Returns:
BlockStructure - The deserialized block structure starting
at root_block_usage_key, if found.
Raises:
BlockStructureNotFound if the root_block_usage_key is not
found.
"""
bs_model
=
self
.
_get_model
(
root_block_usage_key
)
try
:
serialized_data
=
self
.
_get_from_cache
(
bs_model
)
except
BlockStructureNotFound
:
serialized_data
=
self
.
_get_from_store
(
bs_model
)
return
self
.
_deserialize
(
serialized_data
,
root_block_usage_key
)
def
delete
(
self
,
root_block_usage_key
):
"""
Deletes the block structure for the given root_block_usage_key
from the cache and storage.
Arguments:
root_block_usage_key (UsageKey) - The usage_key for the root
of the block structure that is to be removed.
"""
bs_model
=
self
.
_get_model
(
root_block_usage_key
)
self
.
_cache
.
delete
(
self
.
_encode_root_cache_key
(
bs_model
))
bs_model
.
delete
()
logger
.
info
(
"BlockStructure: Deleted from cache and store;
%
r."
,
bs_model
)
def
is_up_to_date
(
self
,
root_block_usage_key
,
modulestore
):
"""
Returns whether the data in storage for the given key is
already up-to-date with the version in the given modulestore.
"""
if
_is_storage_backing_enabled
():
try
:
bs_model
=
self
.
_get_model
(
root_block_usage_key
)
root_block
=
modulestore
.
get_item
(
root_block_usage_key
)
return
self
.
_version_data_of_model
(
bs_model
)
==
self
.
_version_data_of_block
(
root_block
)
except
BlockStructureNotFound
:
pass
return
False
def
_get_model
(
self
,
root_block_usage_key
):
"""
Returns the model associated with the given key.
"""
if
_is_storage_backing_enabled
():
return
BlockStructureModel
.
get
(
root_block_usage_key
)
else
:
return
StubModel
(
root_block_usage_key
)
def
_update_or_create_model
(
self
,
block_structure
,
serialized_data
):
"""
Updates or creates the model for the given block_structure
and serialized_data.
"""
if
_is_storage_backing_enabled
():
root_block
=
block_structure
[
block_structure
.
root_block_usage_key
]
bs_model
,
_
=
BlockStructureModel
.
update_or_create
(
serialized_data
,
data_usage_key
=
block_structure
.
root_block_usage_key
,
**
self
.
_version_data_of_block
(
root_block
)
)
return
bs_model
else
:
return
StubModel
(
block_structure
.
root_block_usage_key
)
def
_add_to_cache
(
self
,
serialized_data
,
bs_model
):
"""
Adds the given serialized_data for the given BlockStructureModel
to the cache.
"""
cache_key
=
self
.
_encode_root_cache_key
(
bs_model
)
self
.
_cache
.
set
(
cache_key
,
serialized_data
,
timeout
=
config
.
cache_timeout_in_seconds
())
logger
.
info
(
"BlockStructure: Added to cache;
%
r, size:
%
d"
,
bs_model
,
len
(
serialized_data
))
def
_get_from_cache
(
self
,
bs_model
):
"""
Returns the serialized data for the given BlockStructureModel
from the cache.
Raises:
BlockStructureNotFound if not found.
"""
cache_key
=
self
.
_encode_root_cache_key
(
bs_model
)
serialized_data
=
self
.
_cache
.
get
(
cache_key
)
if
not
serialized_data
:
logger
.
info
(
"BlockStructure: Not found in cache;
%
r."
,
bs_model
)
raise
BlockStructureNotFound
(
bs_model
.
data_usage_key
)
else
:
logger
.
info
(
"BlockStructure: Read from cache;
%
r, size:
%
d"
,
bs_model
,
len
(
serialized_data
))
return
serialized_data
def
_get_from_store
(
self
,
bs_model
):
"""
Returns the serialized data for the given BlockStructureModel
from storage.
Raises:
BlockStructureNotFound if not found.
"""
if
not
_is_storage_backing_enabled
():
raise
BlockStructureNotFound
(
bs_model
.
data_usage_key
)
return
bs_model
.
get_serialized_data
()
def
_serialize
(
self
,
block_structure
):
"""
Serializes the data for the given block_structure.
"""
data_to_cache
=
(
block_structure
.
_block_relations
,
block_structure
.
transformer_data
,
block_structure
.
_block_data_map
,
)
return
zpickle
(
data_to_cache
)
def
_deserialize
(
self
,
serialized_data
,
root_block_usage_key
):
"""
Deserializes the given data and returns the parsed block_structure.
"""
block_relations
,
transformer_data
,
block_data_map
=
zunpickle
(
serialized_data
)
return
BlockStructureFactory
.
create_new
(
root_block_usage_key
,
block_relations
,
transformer_data
,
block_data_map
,
)
@staticmethod
def
_encode_root_cache_key
(
bs_model
):
"""
Returns the cache key to use for the given
BlockStructureModel or StubModel.
"""
if
_is_storage_backing_enabled
():
return
unicode
(
bs_model
)
else
:
return
"v{version}.root.key.{root_usage_key}"
.
format
(
version
=
unicode
(
BlockStructureBlockData
.
VERSION
),
root_usage_key
=
unicode
(
bs_model
.
data_usage_key
),
)
@staticmethod
def
_version_data_of_block
(
root_block
):
"""
Returns the version-relevant data for the given block, including the
current schema state of the Transformers and BlockStructure classes.
"""
return
dict
(
data_version
=
getattr
(
root_block
,
'course_version'
,
None
),
data_edit_timestamp
=
getattr
(
root_block
,
'subtree_edited_on'
,
None
),
transformers_schema_version
=
TransformerRegistry
.
get_write_version_hash
(),
block_structure_schema_version
=
unicode
(
BlockStructureBlockData
.
VERSION
),
)
@staticmethod
def
_version_data_of_model
(
bs_model
):
"""
Returns the version-relevant data for the given BlockStructureModel.
"""
return
{
field_name
:
getattr
(
bs_model
,
field_name
,
None
)
for
field_name
in
BlockStructureModel
.
VERSION_FIELDS
}
def
_is_storage_backing_enabled
():
"""
Returns whether storage backing for Block Structures is enabled.
"""
return
config
.
is_enabled
(
config
.
STORAGE_BACKING_FOR_CACHE
)
openedx/core/lib/block_structure/tests/helpers.py
View file @
1ee2c27f
...
@@ -4,6 +4,9 @@ Common utilities for tests in block_structure module
...
@@ -4,6 +4,9 @@ Common utilities for tests in block_structure module
from
contextlib
import
contextmanager
from
contextlib
import
contextmanager
from
mock
import
patch
from
mock
import
patch
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
uuid
import
uuid4
from
opaque_keys.edx.locator
import
CourseLocator
,
BlockUsageLocator
from
..block_structure
import
BlockStructureBlockData
from
..block_structure
import
BlockStructureBlockData
from
..transformer
import
BlockStructureTransformer
,
FilteringTransformerMixin
from
..transformer
import
BlockStructureTransformer
,
FilteringTransformerMixin
...
@@ -115,7 +118,7 @@ class MockModulestoreFactory(object):
...
@@ -115,7 +118,7 @@ class MockModulestoreFactory(object):
A factory for creating MockModulestore objects.
A factory for creating MockModulestore objects.
"""
"""
@classmethod
@classmethod
def
create
(
cls
,
children_map
):
def
create
(
cls
,
children_map
,
block_key_factory
):
"""
"""
Creates and returns a MockModulestore from the given
Creates and returns a MockModulestore from the given
children_map.
children_map.
...
@@ -127,7 +130,11 @@ class MockModulestoreFactory(object):
...
@@ -127,7 +130,11 @@ class MockModulestoreFactory(object):
"""
"""
modulestore
=
MockModulestore
()
modulestore
=
MockModulestore
()
modulestore
.
set_blocks
({
modulestore
.
set_blocks
({
block_key
:
MockXBlock
(
block_key
,
children
=
children
,
modulestore
=
modulestore
)
block_key_factory
(
block_key
):
MockXBlock
(
block_key_factory
(
block_key
),
children
=
[
block_key_factory
(
child
)
for
child
in
children
],
modulestore
=
modulestore
,
)
for
block_key
,
children
in
enumerate
(
children_map
)
for
block_key
,
children
in
enumerate
(
children_map
)
})
})
return
modulestore
return
modulestore
...
@@ -216,18 +223,26 @@ class ChildrenMapTestMixin(object):
...
@@ -216,18 +223,26 @@ class ChildrenMapTestMixin(object):
# 5 6
# 5 6
DAG_CHILDREN_MAP
=
[[
1
,
2
],
[
3
],
[
3
,
4
],
[
5
,
6
],
[],
[],
[]]
DAG_CHILDREN_MAP
=
[[
1
,
2
],
[
3
],
[
3
,
4
],
[
5
,
6
],
[],
[],
[]]
def
block_key_factory
(
self
,
block_id
):
"""
Returns a block key object for the given block_id.
Override this method if the block_key should be anything
different from the index integer values in the Children Maps.
"""
return
block_id
def
create_block_structure
(
self
,
children_map
,
block_structure_cls
=
BlockStructureBlockData
):
def
create_block_structure
(
self
,
children_map
,
block_structure_cls
=
BlockStructureBlockData
):
"""
"""
Factory method for creating and returning a block structure
Factory method for creating and returning a block structure
for the given children_map.
for the given children_map.
"""
"""
# create empty block structure
# create empty block structure
block_structure
=
block_structure_cls
(
root_block_usage_key
=
0
)
block_structure
=
block_structure_cls
(
root_block_usage_key
=
self
.
block_key_factory
(
0
)
)
# _add_relation
# _add_relation
for
parent
,
children
in
enumerate
(
children_map
):
for
parent
,
children
in
enumerate
(
children_map
):
for
child
in
children
:
for
child
in
children
:
block_structure
.
_add_relation
(
parent
,
child
)
# pylint: disable=protected-access
block_structure
.
_add_relation
(
self
.
block_key_factory
(
parent
),
self
.
block_key_factory
(
child
)
)
# pylint: disable=protected-access
return
block_structure
return
block_structure
def
get_parents_map
(
self
,
children_map
):
def
get_parents_map
(
self
,
children_map
):
...
@@ -253,8 +268,8 @@ class ChildrenMapTestMixin(object):
...
@@ -253,8 +268,8 @@ class ChildrenMapTestMixin(object):
for
block_key
,
children
in
enumerate
(
children_map
):
for
block_key
,
children
in
enumerate
(
children_map
):
# Verify presence
# Verify presence
self
.
assertEqual
s
(
self
.
assertEqual
(
block_key
in
block_structure
,
self
.
block_key_factory
(
block_key
)
in
block_structure
,
block_key
not
in
missing_blocks
,
block_key
not
in
missing_blocks
,
'Expected presence in block_structure for block_key {} to match absence in missing_blocks.'
.
format
(
'Expected presence in block_structure for block_key {} to match absence in missing_blocks.'
.
format
(
unicode
(
block_key
)
unicode
(
block_key
)
...
@@ -263,16 +278,33 @@ class ChildrenMapTestMixin(object):
...
@@ -263,16 +278,33 @@ class ChildrenMapTestMixin(object):
# Verify children
# Verify children
if
block_key
not
in
missing_blocks
:
if
block_key
not
in
missing_blocks
:
self
.
assertEqual
s
(
self
.
assertEqual
(
set
(
block_structure
.
get_children
(
block_key
)),
set
(
block_structure
.
get_children
(
self
.
block_key_factory
(
block_key
)
)),
set
(
children
),
set
(
self
.
block_key_factory
(
child
)
for
child
in
children
),
)
)
# Verify parents
# Verify parents
parents_map
=
self
.
get_parents_map
(
children_map
)
parents_map
=
self
.
get_parents_map
(
children_map
)
for
block_key
,
parents
in
enumerate
(
parents_map
):
for
block_key
,
parents
in
enumerate
(
parents_map
):
if
block_key
not
in
missing_blocks
:
if
block_key
not
in
missing_blocks
:
self
.
assertEqual
s
(
self
.
assertEqual
(
set
(
block_structure
.
get_parents
(
block_key
)),
set
(
block_structure
.
get_parents
(
self
.
block_key_factory
(
block_key
)
)),
set
(
parents
),
set
(
self
.
block_key_factory
(
parent
)
for
parent
in
parents
),
)
)
class
UsageKeyFactoryMixin
(
object
):
"""
Test Mixin that provides a block_key_factory to create OpaqueKey objects
for block_ids rather than simple integers. By default, the children maps in
ChildrenMapTestMixin use integers for block_ids.
"""
def
setUp
(
self
):
super
(
UsageKeyFactoryMixin
,
self
)
.
setUp
()
self
.
course_key
=
CourseLocator
(
'org'
,
'course'
,
unicode
(
uuid4
()))
def
block_key_factory
(
self
,
block_id
):
"""
Returns a block key object for the given block_id.
"""
return
BlockUsageLocator
(
course_key
=
self
.
course_key
,
block_type
=
'course'
,
block_id
=
unicode
(
block_id
))
openedx/core/lib/block_structure/tests/test_cache.py
deleted
100644 → 0
View file @
77a29242
"""
Tests for block_structure/cache.py
"""
from
nose.plugins.attrib
import
attr
from
unittest
import
TestCase
from
..cache
import
BlockStructureCache
from
.helpers
import
ChildrenMapTestMixin
,
MockCache
,
MockTransformer
@attr
(
shard
=
2
)
class
TestBlockStructureCache
(
ChildrenMapTestMixin
,
TestCase
):
"""
Tests for BlockStructureCache
"""
def
setUp
(
self
):
super
(
TestBlockStructureCache
,
self
)
.
setUp
()
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
block_structure
=
self
.
create_block_structure
(
self
.
children_map
)
self
.
mock_cache
=
MockCache
()
self
.
block_structure_cache
=
BlockStructureCache
(
self
.
mock_cache
)
def
add_transformers
(
self
):
"""
Add each registered transformer to the block structure.
Mimic collection by setting test transformer block data.
"""
for
transformer
in
[
MockTransformer
]:
self
.
block_structure
.
_add_transformer
(
transformer
)
# pylint: disable=protected-access
self
.
block_structure
.
set_transformer_block_field
(
usage_key
=
0
,
transformer
=
transformer
,
key
=
'test'
,
value
=
'{} val'
.
format
(
transformer
.
name
())
)
def
test_add_and_get
(
self
):
self
.
assertEquals
(
self
.
mock_cache
.
timeout_from_last_call
,
0
)
self
.
add_transformers
()
self
.
block_structure_cache
.
add
(
self
.
block_structure
)
self
.
assertEquals
(
self
.
mock_cache
.
timeout_from_last_call
,
60
*
60
*
24
)
cached_value
=
self
.
block_structure_cache
.
get
(
self
.
block_structure
.
root_block_usage_key
)
self
.
assertIsNotNone
(
cached_value
)
self
.
assert_block_structure
(
cached_value
,
self
.
children_map
)
def
test_get_none
(
self
):
self
.
assertIsNone
(
self
.
block_structure_cache
.
get
(
self
.
block_structure
.
root_block_usage_key
)
)
def
test_delete
(
self
):
self
.
add_transformers
()
self
.
block_structure_cache
.
add
(
self
.
block_structure
)
self
.
block_structure_cache
.
delete
(
self
.
block_structure
.
root_block_usage_key
)
self
.
assertIsNone
(
self
.
block_structure_cache
.
get
(
self
.
block_structure
.
root_block_usage_key
)
)
openedx/core/lib/block_structure/tests/test_factory.py
View file @
1ee2c27f
...
@@ -5,7 +5,7 @@ from nose.plugins.attrib import attr
...
@@ -5,7 +5,7 @@ from nose.plugins.attrib import attr
from
unittest
import
TestCase
from
unittest
import
TestCase
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
..
cache
import
BlockStructureCach
e
from
..
store
import
BlockStructureStor
e
from
..exceptions
import
BlockStructureNotFound
from
..exceptions
import
BlockStructureNotFound
from
..factory
import
BlockStructureFactory
from
..factory
import
BlockStructureFactory
from
.helpers
import
(
from
.helpers
import
(
...
@@ -21,7 +21,7 @@ class TestBlockStructureFactory(TestCase, ChildrenMapTestMixin):
...
@@ -21,7 +21,7 @@ class TestBlockStructureFactory(TestCase, ChildrenMapTestMixin):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestBlockStructureFactory
,
self
)
.
setUp
()
super
(
TestBlockStructureFactory
,
self
)
.
setUp
()
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
modulestore
=
MockModulestoreFactory
.
create
(
self
.
children_map
)
self
.
modulestore
=
MockModulestoreFactory
.
create
(
self
.
children_map
,
self
.
block_key_factory
)
def
test_from_modulestore
(
self
):
def
test_from_modulestore
(
self
):
block_structure
=
BlockStructureFactory
.
create_from_modulestore
(
block_structure
=
BlockStructureFactory
.
create_from_modulestore
(
...
@@ -37,21 +37,21 @@ class TestBlockStructureFactory(TestCase, ChildrenMapTestMixin):
...
@@ -37,21 +37,21 @@ class TestBlockStructureFactory(TestCase, ChildrenMapTestMixin):
)
)
def
test_from_cache
(
self
):
def
test_from_cache
(
self
):
cache
=
BlockStructureCach
e
(
MockCache
())
store
=
BlockStructureStor
e
(
MockCache
())
block_structure
=
self
.
create_block_structure
(
self
.
children_map
)
block_structure
=
self
.
create_block_structure
(
self
.
children_map
)
cach
e
.
add
(
block_structure
)
stor
e
.
add
(
block_structure
)
from_cache_block_structure
=
BlockStructureFactory
.
create_from_
cach
e
(
from_cache_block_structure
=
BlockStructureFactory
.
create_from_
stor
e
(
block_structure
.
root_block_usage_key
,
block_structure
.
root_block_usage_key
,
cach
e
,
stor
e
,
)
)
self
.
assert_block_structure
(
from_cache_block_structure
,
self
.
children_map
)
self
.
assert_block_structure
(
from_cache_block_structure
,
self
.
children_map
)
def
test_from_cache_none
(
self
):
def
test_from_cache_none
(
self
):
cache
=
BlockStructureCach
e
(
MockCache
())
store
=
BlockStructureStor
e
(
MockCache
())
with
self
.
assertRaises
(
BlockStructureNotFound
):
with
self
.
assertRaises
(
BlockStructureNotFound
):
BlockStructureFactory
.
create_from_
cach
e
(
BlockStructureFactory
.
create_from_
stor
e
(
root_block_usage_key
=
0
,
root_block_usage_key
=
0
,
block_structure_
cache
=
cach
e
,
block_structure_
store
=
stor
e
,
)
)
def
test_new
(
self
):
def
test_new
(
self
):
...
...
openedx/core/lib/block_structure/tests/test_manager.py
View file @
1ee2c27f
"""
"""
Tests for manager.py
Tests for manager.py
"""
"""
import
ddt
from
nose.plugins.attrib
import
attr
from
nose.plugins.attrib
import
attr
from
unittest
import
TestCase
from
unittest
import
TestCase
from
openedx.core.djangoapps.content.block_structure.config
import
RAISE_ERROR_WHEN_NOT_FOUND
,
STORAGE_BACKING_FOR_CACHE
from
openedx.core.djangoapps.content.block_structure.tests.helpers
import
override_config_setting
from
..block_structure
import
BlockStructureBlockData
from
..block_structure
import
BlockStructureBlockData
from
..exceptions
import
UsageKeyNotInBlockStructure
from
..exceptions
import
UsageKeyNotInBlockStructure
,
BlockStructureNotFound
from
..manager
import
BlockStructureManager
from
..manager
import
BlockStructureManager
from
..transformers
import
BlockStructureTransformers
from
..transformers
import
BlockStructureTransformers
from
.helpers
import
(
from
.helpers
import
(
MockModulestoreFactory
,
MockCache
,
MockTransformer
,
ChildrenMapTestMixin
,
mock_registered_transformers
MockModulestoreFactory
,
MockCache
,
MockTransformer
,
ChildrenMapTestMixin
,
UsageKeyFactoryMixin
,
mock_registered_transformers
,
)
)
...
@@ -86,7 +92,8 @@ class TestTransformer1(MockTransformer):
...
@@ -86,7 +92,8 @@ class TestTransformer1(MockTransformer):
@attr
(
shard
=
2
)
@attr
(
shard
=
2
)
class
TestBlockStructureManager
(
TestCase
,
ChildrenMapTestMixin
):
@ddt.ddt
class
TestBlockStructureManager
(
UsageKeyFactoryMixin
,
ChildrenMapTestMixin
,
TestCase
):
"""
"""
Test class for BlockStructureManager.
Test class for BlockStructureManager.
"""
"""
...
@@ -99,13 +106,9 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
...
@@ -99,13 +106,9 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
self
.
transformers
=
BlockStructureTransformers
(
self
.
registered_transformers
)
self
.
transformers
=
BlockStructureTransformers
(
self
.
registered_transformers
)
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
modulestore
=
MockModulestoreFactory
.
create
(
self
.
children_map
)
self
.
modulestore
=
MockModulestoreFactory
.
create
(
self
.
children_map
,
self
.
block_key_factory
)
self
.
cache
=
MockCache
()
self
.
cache
=
MockCache
()
self
.
bs_manager
=
BlockStructureManager
(
self
.
bs_manager
=
BlockStructureManager
(
self
.
block_key_factory
(
0
),
self
.
modulestore
,
self
.
cache
)
root_block_usage_key
=
0
,
modulestore
=
self
.
modulestore
,
cache
=
self
.
cache
,
)
def
collect_and_verify
(
self
,
expect_modulestore_called
,
expect_cache_updated
):
def
collect_and_verify
(
self
,
expect_modulestore_called
,
expect_cache_updated
):
"""
"""
...
@@ -133,7 +136,10 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
...
@@ -133,7 +136,10 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
def
test_get_transformed_with_starting_block
(
self
):
def
test_get_transformed_with_starting_block
(
self
):
with
mock_registered_transformers
(
self
.
registered_transformers
):
with
mock_registered_transformers
(
self
.
registered_transformers
):
block_structure
=
self
.
bs_manager
.
get_transformed
(
self
.
transformers
,
starting_block_usage_key
=
1
)
block_structure
=
self
.
bs_manager
.
get_transformed
(
self
.
transformers
,
starting_block_usage_key
=
self
.
block_key_factory
(
1
),
)
substructure_of_children_map
=
[[],
[
3
,
4
],
[],
[],
[]]
substructure_of_children_map
=
[[],
[
3
,
4
],
[],
[],
[]]
self
.
assert_block_structure
(
block_structure
,
substructure_of_children_map
,
missing_blocks
=
[
0
,
2
])
self
.
assert_block_structure
(
block_structure
,
substructure_of_children_map
,
missing_blocks
=
[
0
,
2
])
TestTransformer1
.
assert_collected
(
block_structure
)
TestTransformer1
.
assert_collected
(
block_structure
)
...
@@ -152,7 +158,7 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
...
@@ -152,7 +158,7 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
]:
]:
block_structure
=
self
.
bs_manager
.
get_transformed
(
block_structure
=
self
.
bs_manager
.
get_transformed
(
self
.
transformers
,
self
.
transformers
,
starting_block_usage_key
=
s
tarting_block
,
starting_block_usage_key
=
s
elf
.
block_key_factory
(
starting_block
)
,
collected_block_structure
=
collected_block_structure
,
collected_block_structure
=
collected_block_structure
,
)
)
self
.
assert_block_structure
(
block_structure
,
expected_structure
,
missing_blocks
=
expected_missing_blocks
)
self
.
assert_block_structure
(
block_structure
,
expected_structure
,
missing_blocks
=
expected_missing_blocks
)
...
@@ -167,6 +173,26 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
...
@@ -167,6 +173,26 @@ class TestBlockStructureManager(TestCase, ChildrenMapTestMixin):
self
.
collect_and_verify
(
expect_modulestore_called
=
False
,
expect_cache_updated
=
False
)
self
.
collect_and_verify
(
expect_modulestore_called
=
False
,
expect_cache_updated
=
False
)
self
.
assertEquals
(
TestTransformer1
.
collect_call_count
,
1
)
self
.
assertEquals
(
TestTransformer1
.
collect_call_count
,
1
)
def
test_get_collected_error_raised
(
self
):
with
override_config_setting
(
RAISE_ERROR_WHEN_NOT_FOUND
,
active
=
True
):
with
mock_registered_transformers
(
self
.
registered_transformers
):
with
self
.
assertRaises
(
BlockStructureNotFound
):
self
.
bs_manager
.
get_collected
()
@ddt.data
(
True
,
False
)
def
test_update_collected_if_needed
(
self
,
with_storage_backing
):
with
override_config_setting
(
STORAGE_BACKING_FOR_CACHE
,
active
=
with_storage_backing
):
with
mock_registered_transformers
(
self
.
registered_transformers
):
self
.
assertEquals
(
TestTransformer1
.
collect_call_count
,
0
)
self
.
bs_manager
.
update_collected_if_needed
()
self
.
assertEquals
(
TestTransformer1
.
collect_call_count
,
1
)
self
.
bs_manager
.
update_collected_if_needed
()
self
.
assertEquals
(
TestTransformer1
.
collect_call_count
,
1
if
with_storage_backing
else
2
)
self
.
collect_and_verify
(
expect_modulestore_called
=
False
,
expect_cache_updated
=
False
)
def
test_get_collected_transformer_version
(
self
):
def
test_get_collected_transformer_version
(
self
):
self
.
collect_and_verify
(
expect_modulestore_called
=
True
,
expect_cache_updated
=
True
)
self
.
collect_and_verify
(
expect_modulestore_called
=
True
,
expect_cache_updated
=
True
)
...
...
openedx/core/lib/block_structure/tests/test_store.py
0 → 100644
View file @
1ee2c27f
"""
Tests for block_structure/cache.py
"""
import
ddt
from
nose.plugins.attrib
import
attr
from
openedx.core.djangoapps.content.block_structure.config
import
STORAGE_BACKING_FOR_CACHE
from
openedx.core.djangoapps.content.block_structure.config.models
import
BlockStructureConfiguration
from
openedx.core.djangoapps.content.block_structure.tests.helpers
import
override_config_setting
from
openedx.core.djangolib.testing.utils
import
CacheIsolationTestCase
from
..store
import
BlockStructureStore
from
..exceptions
import
BlockStructureNotFound
from
.helpers
import
ChildrenMapTestMixin
,
UsageKeyFactoryMixin
,
MockCache
,
MockTransformer
@attr
(
shard
=
2
)
@ddt.ddt
class
TestBlockStructureStore
(
UsageKeyFactoryMixin
,
ChildrenMapTestMixin
,
CacheIsolationTestCase
):
"""
Tests for BlockStructureStore
"""
ENABLED_CACHES
=
[
'default'
]
def
setUp
(
self
):
super
(
TestBlockStructureStore
,
self
)
.
setUp
()
self
.
children_map
=
self
.
SIMPLE_CHILDREN_MAP
self
.
block_structure
=
self
.
create_block_structure
(
self
.
children_map
)
self
.
add_transformers
()
self
.
mock_cache
=
MockCache
()
self
.
store
=
BlockStructureStore
(
self
.
mock_cache
)
def
add_transformers
(
self
):
"""
Add each registered transformer to the block structure.
Mimic collection by setting test transformer block data.
"""
for
transformer
in
[
MockTransformer
]:
self
.
block_structure
.
_add_transformer
(
transformer
)
# pylint: disable=protected-access
self
.
block_structure
.
set_transformer_block_field
(
self
.
block_key_factory
(
0
),
transformer
,
key
=
'test'
,
value
=
'{} val'
.
format
(
transformer
.
name
()),
)
@ddt.data
(
True
,
False
)
def
test_get_none
(
self
,
with_storage_backing
):
with
override_config_setting
(
STORAGE_BACKING_FOR_CACHE
,
active
=
with_storage_backing
):
with
self
.
assertRaises
(
BlockStructureNotFound
):
self
.
store
.
get
(
self
.
block_structure
.
root_block_usage_key
)
@ddt.data
(
True
,
False
)
def
test_add_and_get
(
self
,
with_storage_backing
):
with
override_config_setting
(
STORAGE_BACKING_FOR_CACHE
,
active
=
with_storage_backing
):
self
.
store
.
add
(
self
.
block_structure
)
stored_value
=
self
.
store
.
get
(
self
.
block_structure
.
root_block_usage_key
)
self
.
assertIsNotNone
(
stored_value
)
self
.
assert_block_structure
(
stored_value
,
self
.
children_map
)
@ddt.data
(
True
,
False
)
def
test_delete
(
self
,
with_storage_backing
):
with
override_config_setting
(
STORAGE_BACKING_FOR_CACHE
,
active
=
with_storage_backing
):
self
.
store
.
add
(
self
.
block_structure
)
self
.
store
.
delete
(
self
.
block_structure
.
root_block_usage_key
)
with
self
.
assertRaises
(
BlockStructureNotFound
):
self
.
store
.
get
(
self
.
block_structure
.
root_block_usage_key
)
def
test_uncached_without_storage
(
self
):
self
.
store
.
add
(
self
.
block_structure
)
self
.
mock_cache
.
map
.
clear
()
with
self
.
assertRaises
(
BlockStructureNotFound
):
self
.
store
.
get
(
self
.
block_structure
.
root_block_usage_key
)
def
test_uncached_with_storage
(
self
):
with
override_config_setting
(
STORAGE_BACKING_FOR_CACHE
,
active
=
True
):
self
.
store
.
add
(
self
.
block_structure
)
self
.
mock_cache
.
map
.
clear
()
stored_value
=
self
.
store
.
get
(
self
.
block_structure
.
root_block_usage_key
)
self
.
assert_block_structure
(
stored_value
,
self
.
children_map
)
@ddt.data
(
1
,
5
,
None
)
def
test_cache_timeout
(
self
,
timeout
):
if
timeout
is
not
None
:
BlockStructureConfiguration
.
objects
.
create
(
enabled
=
True
,
cache_timeout_in_seconds
=
timeout
)
else
:
timeout
=
BlockStructureConfiguration
.
DEFAULT_CACHE_TIMEOUT_IN_SECONDS
self
.
assertEquals
(
self
.
mock_cache
.
timeout_from_last_call
,
0
)
self
.
store
.
add
(
self
.
block_structure
)
self
.
assertEquals
(
self
.
mock_cache
.
timeout_from_last_call
,
timeout
)
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