Moved assetstore tests to own file and ddt'd across stores
Conflicts: common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
This commit is contained in:
394
common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py
Normal file
394
common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py
Normal file
@@ -0,0 +1,394 @@
|
||||
"""
|
||||
Tests for assetstore using any of the modulestores for metadata. May extend to testing the storage options
|
||||
too.
|
||||
"""
|
||||
from datetime import datetime, timedelta
|
||||
import pytz
|
||||
import unittest
|
||||
import ddt
|
||||
|
||||
from xmodule.assetstore import AssetMetadata, AssetThumbnailMetadata
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.test_cross_modulestore_import_export import (
|
||||
MODULESTORE_SETUPS, MongoContentstoreBuilder,
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestMongoAssetMetadataStorage(unittest.TestCase):
|
||||
"""
|
||||
Tests for storing/querying course asset metadata.
|
||||
"""
|
||||
def setUp(self):
|
||||
super(TestMongoAssetMetadataStorage, self).setUp()
|
||||
self.addTypeEqualityFunc(datetime, self._compare_datetimes)
|
||||
self.addTypeEqualityFunc(AssetMetadata, self._compare_metadata)
|
||||
|
||||
def _compare_metadata(self, mdata1, mdata2, msg=None):
|
||||
"""
|
||||
So we can use the below date comparison
|
||||
"""
|
||||
if type(mdata1) != type(mdata2):
|
||||
self.fail(self._formatMessage(msg, u"{} is not same type as {}".format(mdata1, mdata2)))
|
||||
for attr in mdata1.ALLOWED_ATTRS:
|
||||
self.assertEqual(getattr(mdata1, attr), getattr(mdata2, attr), msg)
|
||||
|
||||
def _compare_datetimes(self, datetime1, datetime2, msg=None):
|
||||
"""
|
||||
Don't compare microseconds as mongo doesn't encode below milliseconds
|
||||
"""
|
||||
if not timedelta(seconds=-1) < datetime1 - datetime2 < timedelta(seconds=1):
|
||||
self.fail(self._formatMessage(msg, u"{} != {}".format(datetime1, datetime2)))
|
||||
|
||||
def _make_asset_metadata(self, asset_loc):
|
||||
"""
|
||||
Make a single test asset metadata.
|
||||
"""
|
||||
return AssetMetadata(asset_loc, internal_name='EKMND332DDBK',
|
||||
basename='pictures/historical', contenttype='image/jpeg',
|
||||
locked=False, md5='77631ca4f0e08419b70726a447333ab6',
|
||||
edited_by=ModuleStoreEnum.UserID.test, edited_on=datetime.now(pytz.utc),
|
||||
curr_version='v1.0', prev_version='v0.95')
|
||||
|
||||
def _make_asset_thumbnail_metadata(self, asset_key):
|
||||
"""
|
||||
Make a single test asset thumbnail metadata.
|
||||
"""
|
||||
return AssetThumbnailMetadata(asset_key, internal_name='ABC39XJUDN2')
|
||||
|
||||
def setup_assets(self, course1_key, course2_key, store=None):
|
||||
"""
|
||||
Setup assets. Save in store if given
|
||||
"""
|
||||
asset_fields = ('filename', 'internal_name', 'basename', 'locked', 'edited_by', 'edited_on', 'curr_version', 'prev_version')
|
||||
asset1_vals = ('pic1.jpg', 'EKMND332DDBK', 'pix/archive', False, ModuleStoreEnum.UserID.test, datetime.now(pytz.utc), '14', '13')
|
||||
asset2_vals = ('shout.ogg', 'KFMDONSKF39K', 'sounds', True, ModuleStoreEnum.UserID.test, datetime.now(pytz.utc), '1', None)
|
||||
asset3_vals = ('code.tgz', 'ZZB2333YBDMW', 'exercises/14', False, ModuleStoreEnum.UserID.test * 2, datetime.now(pytz.utc), 'AB', 'AA')
|
||||
asset4_vals = ('dog.png', 'PUPY4242X', 'pictures/animals', True, ModuleStoreEnum.UserID.test * 3, datetime.now(pytz.utc), '5', '4')
|
||||
asset5_vals = ('not_here.txt', 'JJJCCC747', '/dev/null', False, ModuleStoreEnum.UserID.test * 4, datetime.now(pytz.utc), '50', '49')
|
||||
|
||||
asset1 = dict(zip(asset_fields[1:], asset1_vals[1:]))
|
||||
asset2 = dict(zip(asset_fields[1:], asset2_vals[1:]))
|
||||
asset3 = dict(zip(asset_fields[1:], asset3_vals[1:]))
|
||||
asset4 = dict(zip(asset_fields[1:], asset4_vals[1:]))
|
||||
non_existent_asset = dict(zip(asset_fields[1:], asset5_vals[1:]))
|
||||
|
||||
# Asset6 and thumbnail6 have equivalent information on purpose.
|
||||
asset6_vals = ('asset.txt', 'JJJCCC747858', '/dev/null', False, ModuleStoreEnum.UserID.test * 4, datetime.now(pytz.utc), '50', '49')
|
||||
asset6 = dict(zip(asset_fields[1:], asset6_vals[1:]))
|
||||
|
||||
asset1_key = course1_key.make_asset_key('asset', asset1_vals[0])
|
||||
asset2_key = course1_key.make_asset_key('asset', asset2_vals[0])
|
||||
asset3_key = course2_key.make_asset_key('asset', asset3_vals[0])
|
||||
asset4_key = course2_key.make_asset_key('asset', asset4_vals[0])
|
||||
asset5_key = course2_key.make_asset_key('asset', asset5_vals[0])
|
||||
asset6_key = course2_key.make_asset_key('asset', asset6_vals[0])
|
||||
|
||||
asset1_md = AssetMetadata(asset1_key, **asset1)
|
||||
asset2_md = AssetMetadata(asset2_key, **asset2)
|
||||
asset3_md = AssetMetadata(asset3_key, **asset3)
|
||||
asset4_md = AssetMetadata(asset4_key, **asset4)
|
||||
asset5_md = AssetMetadata(asset5_key, **non_existent_asset)
|
||||
asset6_md = AssetMetadata(asset6_key, **asset6)
|
||||
|
||||
if store is not None:
|
||||
store.save_asset_metadata(course1_key, asset1_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_metadata(course1_key, asset2_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_metadata(course2_key, asset3_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_metadata(course2_key, asset4_md, ModuleStoreEnum.UserID.test)
|
||||
# 5 & 6 are not saved on purpose!
|
||||
|
||||
return (asset1_md, asset2_md, asset3_md, asset4_md, asset5_md, asset6_md)
|
||||
|
||||
def setup_thumbnails(self, course1_key, course2_key, store=None):
|
||||
"""
|
||||
Setup thumbs. Save in store if given
|
||||
"""
|
||||
thumbnail_fields = ('filename', 'internal_name')
|
||||
thumbnail1_vals = ('cat_thumb.jpg', 'XYXYXYXYXYXY')
|
||||
thumbnail2_vals = ('kitten_thumb.jpg', '123ABC123ABC')
|
||||
thumbnail3_vals = ('puppy_thumb.jpg', 'ADAM12ADAM12')
|
||||
thumbnail4_vals = ('meerkat_thumb.jpg', 'CHIPSPONCH14')
|
||||
thumbnail5_vals = ('corgi_thumb.jpg', 'RON8LDXFFFF10')
|
||||
|
||||
thumbnail1 = dict(zip(thumbnail_fields[1:], thumbnail1_vals[1:]))
|
||||
thumbnail2 = dict(zip(thumbnail_fields[1:], thumbnail2_vals[1:]))
|
||||
thumbnail3 = dict(zip(thumbnail_fields[1:], thumbnail3_vals[1:]))
|
||||
thumbnail4 = dict(zip(thumbnail_fields[1:], thumbnail4_vals[1:]))
|
||||
non_existent_thumbnail = dict(zip(thumbnail_fields[1:], thumbnail5_vals[1:]))
|
||||
|
||||
# Asset6 and thumbnail6 have equivalent information on purpose.
|
||||
thumbnail6_vals = ('asset.txt', 'JJJCCC747858')
|
||||
thumbnail6 = dict(zip(thumbnail_fields[1:], thumbnail6_vals[1:]))
|
||||
|
||||
thumb1_key = course1_key.make_asset_key('thumbnail', thumbnail1_vals[0])
|
||||
thumb2_key = course1_key.make_asset_key('thumbnail', thumbnail2_vals[0])
|
||||
thumb3_key = course2_key.make_asset_key('thumbnail', thumbnail3_vals[0])
|
||||
thumb4_key = course2_key.make_asset_key('thumbnail', thumbnail4_vals[0])
|
||||
thumb5_key = course2_key.make_asset_key('thumbnail', thumbnail5_vals[0])
|
||||
thumb6_key = course2_key.make_asset_key('thumbnail', thumbnail6_vals[0])
|
||||
|
||||
thumb1_md = AssetThumbnailMetadata(thumb1_key, **thumbnail1)
|
||||
thumb2_md = AssetThumbnailMetadata(thumb2_key, **thumbnail2)
|
||||
thumb3_md = AssetThumbnailMetadata(thumb3_key, **thumbnail3)
|
||||
thumb4_md = AssetThumbnailMetadata(thumb4_key, **thumbnail4)
|
||||
thumb5_md = AssetThumbnailMetadata(thumb5_key, **non_existent_thumbnail)
|
||||
thumb6_md = AssetThumbnailMetadata(thumb6_key, **thumbnail6)
|
||||
|
||||
if store is not None:
|
||||
store.save_asset_thumbnail_metadata(course1_key, thumb1_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_thumbnail_metadata(course1_key, thumb2_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_thumbnail_metadata(course2_key, thumb3_md, ModuleStoreEnum.UserID.test)
|
||||
store.save_asset_thumbnail_metadata(course2_key, thumb4_md, ModuleStoreEnum.UserID.test)
|
||||
# thumb5 and thumb6 are not saved on purpose!
|
||||
|
||||
return (thumb1_md, thumb2_md, thumb3_md, thumb4_md, thumb5_md, thumb6_md)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_save_one_and_confirm(self, storebuilder):
|
||||
"""
|
||||
Save the metadata in each store and retrieve it singularly, as all assets, and after deleting all.
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
|
||||
asset_filename = 'burnside.jpg'
|
||||
new_asset_loc = course.id.make_asset_key('asset', asset_filename)
|
||||
# Confirm that the asset's metadata is not present.
|
||||
self.assertIsNone(store.find_asset_metadata(new_asset_loc))
|
||||
# Save the asset's metadata.
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
# Find the asset's metadata and confirm it's the same.
|
||||
found_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(found_asset_md)
|
||||
self.assertEquals(new_asset_md, found_asset_md)
|
||||
# Confirm that only two setup plus one asset's metadata exists.
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 1)
|
||||
# Delete all metadata and confirm it's gone.
|
||||
store.delete_all_asset_metadata(course.id, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 0)
|
||||
# Now delete the non-existent metadata and ensure it doesn't choke
|
||||
store.delete_all_asset_metadata(course.id, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_delete(self, storebuilder):
|
||||
"""
|
||||
Delete non_existent and existent metadata
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
# Attempt to delete an asset that doesn't exist.
|
||||
self.assertEquals(store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test), 0)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test), 1)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_find_non_existing_assets(self, storebuilder):
|
||||
"""
|
||||
Save multiple metadata in each store and retrieve it singularly, as all assets, and after deleting all.
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
# Find existing asset metadata.
|
||||
asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNone(asset_md)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_add_same_asset_twice(self, storebuilder):
|
||||
"""
|
||||
Save multiple metadata in each store and retrieve it singularly, as all assets, and after deleting all.
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
# Add asset metadata.
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 1)
|
||||
# Add *the same* asset metadata.
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
# Still one here?
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 1)
|
||||
store.delete_all_asset_metadata(course.id, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_lock_unlock_assets(self, storebuilder):
|
||||
"""
|
||||
Save multiple metadata in each store and retrieve it singularly, as all assets, and after deleting all.
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
|
||||
locked_state = new_asset_md.locked
|
||||
# Flip the course asset's locked status.
|
||||
store.set_asset_metadata_attr(new_asset_loc, "locked", not locked_state, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its locked status.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertEquals(updated_asset_md.locked, not locked_state)
|
||||
# Now flip it back.
|
||||
store.set_asset_metadata_attr(new_asset_loc, "locked", locked_state, ModuleStoreEnum.UserID.test)
|
||||
reupdated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(reupdated_asset_md)
|
||||
self.assertEquals(reupdated_asset_md.locked, locked_state)
|
||||
|
||||
ALLOWED_ATTRS = (
|
||||
('basename', '/new/path'),
|
||||
('internal_name', 'new_filename.txt'),
|
||||
('locked', True),
|
||||
('contenttype', 'image/png'),
|
||||
('md5', '5346682d948cc3f683635b6918f9b3d0'),
|
||||
('curr_version', 'v1.01'),
|
||||
('prev_version', 'v1.0'),
|
||||
('edited_by', 'Mork'),
|
||||
('edited_on', datetime(1969, 1, 1, tzinfo=pytz.utc)),
|
||||
)
|
||||
|
||||
DISALLOWED_ATTRS = (
|
||||
('asset_id', 'IAmBogus'),
|
||||
)
|
||||
|
||||
UNKNOWN_ATTRS = (
|
||||
('lunch_order', 'burger_and_fries'),
|
||||
('villain', 'Khan')
|
||||
)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_set_all_attrs(self, storebuilder):
|
||||
"""
|
||||
Save setting each attr one at a time
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
for attr, value in self.ALLOWED_ATTRS:
|
||||
# Set the course asset's attr.
|
||||
store.set_asset_metadata_attr(new_asset_loc, attr, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course asset and check its changed attr.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attr, None))
|
||||
self.assertEquals(getattr(updated_asset_md, attr, None), value)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_set_disallowed_attrs(self, storebuilder):
|
||||
"""
|
||||
setting disallowed attrs should fail
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
for attr, value in self.DISALLOWED_ATTRS:
|
||||
original_attr_val = getattr(new_asset_md, attr)
|
||||
# Set the course asset's attr.
|
||||
store.set_asset_metadata_attr(new_asset_loc, attr, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its changed attr.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attr, None))
|
||||
# Make sure that the attr is unchanged from its original value.
|
||||
self.assertEquals(getattr(updated_asset_md, attr, None), original_attr_val)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_set_unknown_attrs(self, storebuilder):
|
||||
"""
|
||||
setting unknown attrs should fail
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(course.id, new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
for attr, value in self.UNKNOWN_ATTRS:
|
||||
# Set the course asset's attr.
|
||||
store.set_asset_metadata_attr(new_asset_loc, attr, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its changed attr.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
# Make sure the unknown field was *not* added.
|
||||
with self.assertRaises(AttributeError):
|
||||
self.assertEquals(getattr(updated_asset_md, attr), value)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_save_one_thumbnail_and_delete_one_thumbnail(self, storebuilder):
|
||||
"""
|
||||
saving and deleting thumbnails
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
thumbnail_filename = 'burn_thumb.jpg'
|
||||
asset_key = course.id.make_asset_key('thumbnail', thumbnail_filename)
|
||||
new_asset_thumbnail = self._make_asset_thumbnail_metadata(asset_key)
|
||||
store.save_asset_thumbnail_metadata(course.id, new_asset_thumbnail, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_thumbnail_metadata(course.id)), 1)
|
||||
self.assertEquals(store.delete_asset_thumbnail_metadata(asset_key, ModuleStoreEnum.UserID.test), 1)
|
||||
self.assertEquals(len(store.get_all_asset_thumbnail_metadata(course.id)), 0)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_find_thumbnail(self, storebuilder):
|
||||
"""
|
||||
finding thumbnails
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
thumbnail_filename = 'burn_thumb.jpg'
|
||||
asset_key = course.id.make_asset_key('thumbnail', thumbnail_filename)
|
||||
new_asset_thumbnail = self._make_asset_thumbnail_metadata(asset_key)
|
||||
store.save_asset_thumbnail_metadata(course.id, new_asset_thumbnail, ModuleStoreEnum.UserID.test)
|
||||
|
||||
self.assertIsNotNone(store.find_asset_thumbnail_metadata(asset_key))
|
||||
unknown_asset_key = course.id.make_asset_key('thumbnail', 'nosuchfile.jpg')
|
||||
self.assertIsNone(store.find_asset_thumbnail_metadata(unknown_asset_key))
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_delete_all_thumbnails(self, storebuilder):
|
||||
"""
|
||||
deleting all thumbnails
|
||||
"""
|
||||
with MongoContentstoreBuilder().build() as contentstore:
|
||||
with storebuilder.build(contentstore) as store:
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
thumbnail_filename = 'burn_thumb.jpg'
|
||||
asset_key = course.id.make_asset_key('thumbnail', thumbnail_filename)
|
||||
new_asset_thumbnail = self._make_asset_thumbnail_metadata(asset_key)
|
||||
store.save_asset_thumbnail_metadata(
|
||||
course.id, new_asset_thumbnail, ModuleStoreEnum.UserID.test
|
||||
)
|
||||
|
||||
self.assertEquals(len(store.get_all_asset_thumbnail_metadata(course.id)), 1)
|
||||
store.delete_all_asset_metadata(course.id, ModuleStoreEnum.UserID.test)
|
||||
self.assertEquals(len(store.get_all_asset_thumbnail_metadata(course.id)), 0)
|
||||
|
||||
def test_get_all_assets_with_paging(self):
|
||||
pass
|
||||
|
||||
def test_copy_all_assets(self):
|
||||
pass
|
||||
@@ -87,6 +87,7 @@ class MongoModulestoreBuilder(object):
|
||||
doc_store_config = dict(
|
||||
db='modulestore{}'.format(random.randint(0, 10000)),
|
||||
collection='xmodule',
|
||||
asset_collection='asset_metadata',
|
||||
**COMMON_DOCSTORE_CONFIG
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from datetime import datetime
|
||||
from pytz import UTC
|
||||
import unittest
|
||||
from xblock.core import XBlock
|
||||
from ddt import ddt, data
|
||||
|
||||
from xblock.fields import Scope, Reference, ReferenceList, ReferenceValueDict
|
||||
from xblock.runtime import KeyValueStore
|
||||
@@ -31,7 +30,6 @@ from opaque_keys.edx.keys import UsageKey
|
||||
from xmodule.modulestore.xml_exporter import export_to_xml
|
||||
from xmodule.modulestore.xml_importer import import_from_xml, perform_xlint
|
||||
from xmodule.contentstore.mongo import MongoContentStore
|
||||
from xmodule.assetstore import AssetMetadata, AssetThumbnailMetadata
|
||||
|
||||
from nose.tools import assert_in
|
||||
from xmodule.exceptions import NotFoundError
|
||||
@@ -665,332 +663,6 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
shutil.rmtree(root_dir)
|
||||
|
||||
|
||||
@ddt
|
||||
class TestMongoAssetMetadataStorage(TestMongoModuleStore):
|
||||
"""
|
||||
Tests for storing/querying course asset metadata from Mongo storage.
|
||||
"""
|
||||
def _make_asset_metadata(self, asset_loc):
|
||||
"""
|
||||
Make a single test asset metadata.
|
||||
"""
|
||||
return AssetMetadata(asset_loc, internal_name='EKMND332DDBK',
|
||||
basename='pictures/historical', contenttype='image/jpeg',
|
||||
locked=False, md5='77631ca4f0e08419b70726a447333ab6',
|
||||
curr_version='v1.0', prev_version='v0.95')
|
||||
|
||||
def _make_asset_thumbnail_metadata(self, asset_key):
|
||||
"""
|
||||
Make a single test asset thumbnail metadata.
|
||||
"""
|
||||
return AssetThumbnailMetadata(asset_key, internal_name='ABC39XJUDN2')
|
||||
|
||||
@classmethod
|
||||
def add_asset_collection(cls, doc_store_config):
|
||||
"""
|
||||
Valid asset collection.
|
||||
"""
|
||||
doc_store_config['asset_collection'] = ASSET_COLLECTION
|
||||
|
||||
@classmethod
|
||||
def setupClass(cls):
|
||||
super(TestMongoAssetMetadataStorage, cls).setupClass()
|
||||
|
||||
@classmethod
|
||||
def teardownClass(cls):
|
||||
super(TestMongoAssetMetadataStorage, cls).teardownClass()
|
||||
|
||||
def setup_assets(self):
|
||||
"""
|
||||
Setup assets.
|
||||
"""
|
||||
asset_fields = ('filename', 'internal_name', 'basename', 'locked', 'curr_version', 'prev_version')
|
||||
asset1_vals = ('pic1.jpg', 'EKMND332DDBK', 'pix/archive', False, '14', '13')
|
||||
asset2_vals = ('shout.ogg', 'KFMDONSKF39K', 'sounds', True, '1', None)
|
||||
asset3_vals = ('code.tgz', 'ZZB2333YBDMW', 'exercises/14', False, 'AB', 'AA')
|
||||
asset4_vals = ('dog.png', 'PUPY4242X', 'pictures/animals', True, '5', '4')
|
||||
asset5_vals = ('not_here.txt', 'JJJCCC747', '/dev/null', False, '50', '49')
|
||||
|
||||
asset1 = dict(zip(asset_fields[1:], asset1_vals[1:]))
|
||||
asset2 = dict(zip(asset_fields[1:], asset2_vals[1:]))
|
||||
asset3 = dict(zip(asset_fields[1:], asset3_vals[1:]))
|
||||
asset4 = dict(zip(asset_fields[1:], asset4_vals[1:]))
|
||||
non_existent_asset = dict(zip(asset_fields[1:], asset5_vals[1:]))
|
||||
|
||||
# Asset6 and thumbnail6 have equivalent information on purpose.
|
||||
asset6_vals = ('asset.txt', 'JJJCCC747858', '/dev/null', False, '50', '49')
|
||||
asset6 = dict(zip(asset_fields[1:], asset6_vals[1:]))
|
||||
|
||||
asset1_key = self.course1.id.make_asset_key('asset', asset1_vals[0])
|
||||
asset2_key = self.course1.id.make_asset_key('asset', asset2_vals[0])
|
||||
asset3_key = self.course2.id.make_asset_key('asset', asset3_vals[0])
|
||||
asset4_key = self.course2.id.make_asset_key('asset', asset4_vals[0])
|
||||
asset5_key = self.course2.id.make_asset_key('asset', asset5_vals[0])
|
||||
asset6_key = self.course2.id.make_asset_key('asset', asset6_vals[0])
|
||||
|
||||
asset1_md = AssetMetadata(asset1_key, **asset1)
|
||||
asset2_md = AssetMetadata(asset2_key, **asset2)
|
||||
asset3_md = AssetMetadata(asset3_key, **asset3)
|
||||
asset4_md = AssetMetadata(asset4_key, **asset4)
|
||||
asset5_md = AssetMetadata(asset5_key, **non_existent_asset)
|
||||
asset6_md = AssetMetadata(asset6_key, **asset6)
|
||||
|
||||
editing_user = 'Oliver Twist'
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(self.course1.id, asset1_md, editing_user))
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(self.course1.id, asset2_md, editing_user))
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(self.course2.id, asset3_md, editing_user))
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(self.course2.id, asset4_md, editing_user))
|
||||
# asset5 and asset6 are not saved on purpose!
|
||||
|
||||
return (asset1_md, asset2_md, asset3_md, asset4_md, asset5_md, asset6_md)
|
||||
|
||||
def setup_thumbnails(self):
|
||||
"""
|
||||
Setup thumbs.
|
||||
"""
|
||||
thumbnail_fields = ('filename', 'internal_name')
|
||||
thumbnail1_vals = ('cat_thumb.jpg', 'XYXYXYXYXYXY')
|
||||
thumbnail2_vals = ('kitten_thumb.jpg', '123ABC123ABC')
|
||||
thumbnail3_vals = ('puppy_thumb.jpg', 'ADAM12ADAM12')
|
||||
thumbnail4_vals = ('meerkat_thumb.jpg', 'CHIPSPONCH14')
|
||||
thumbnail5_vals = ('corgi_thumb.jpg', 'RON8LDXFFFF10')
|
||||
|
||||
thumbnail1 = dict(zip(thumbnail_fields[1:], thumbnail1_vals[1:]))
|
||||
thumbnail2 = dict(zip(thumbnail_fields[1:], thumbnail2_vals[1:]))
|
||||
thumbnail3 = dict(zip(thumbnail_fields[1:], thumbnail3_vals[1:]))
|
||||
thumbnail4 = dict(zip(thumbnail_fields[1:], thumbnail4_vals[1:]))
|
||||
non_existent_thumbnail = dict(zip(thumbnail_fields[1:], thumbnail5_vals[1:]))
|
||||
|
||||
# Asset6 and thumbnail6 have equivalent information on purpose.
|
||||
thumbnail6_vals = ('asset.txt', 'JJJCCC747858')
|
||||
thumbnail6 = dict(zip(thumbnail_fields[1:], thumbnail6_vals[1:]))
|
||||
|
||||
thumb1_key = self.course1.id.make_asset_key('thumbnail', thumbnail1_vals[0])
|
||||
thumb2_key = self.course1.id.make_asset_key('thumbnail', thumbnail2_vals[0])
|
||||
thumb3_key = self.course2.id.make_asset_key('thumbnail', thumbnail3_vals[0])
|
||||
thumb4_key = self.course2.id.make_asset_key('thumbnail', thumbnail4_vals[0])
|
||||
thumb5_key = self.course2.id.make_asset_key('thumbnail', thumbnail5_vals[0])
|
||||
thumb6_key = self.course2.id.make_asset_key('thumbnail', thumbnail6_vals[0])
|
||||
|
||||
thumb1_md = AssetThumbnailMetadata(thumb1_key, **thumbnail1)
|
||||
thumb2_md = AssetThumbnailMetadata(thumb2_key, **thumbnail2)
|
||||
thumb3_md = AssetThumbnailMetadata(thumb3_key, **thumbnail3)
|
||||
thumb4_md = AssetThumbnailMetadata(thumb4_key, **thumbnail4)
|
||||
thumb5_md = AssetThumbnailMetadata(thumb5_key, **non_existent_thumbnail)
|
||||
thumb6_md = AssetThumbnailMetadata(thumb6_key, **thumbnail6)
|
||||
|
||||
self.assertTrue(self.draft_store.save_asset_thumbnail_metadata(self.course1.id, thumb1_md))
|
||||
self.assertTrue(self.draft_store.save_asset_thumbnail_metadata(self.course1.id, thumb2_md))
|
||||
self.assertTrue(self.draft_store.save_asset_thumbnail_metadata(self.course2.id, thumb3_md))
|
||||
self.assertTrue(self.draft_store.save_asset_thumbnail_metadata(self.course2.id, thumb4_md))
|
||||
# thumb5 and thumb6 are not saved on purpose!
|
||||
|
||||
return (thumb1_md, thumb2_md, thumb3_md, thumb4_md, thumb5_md, thumb6_md)
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up a quantity of test asset metadata for testing purposes.
|
||||
"""
|
||||
super(TestMongoAssetMetadataStorage, self).setUp()
|
||||
|
||||
courses = self.draft_store.get_courses()
|
||||
self.course1 = courses[0]
|
||||
self.course2 = courses[1]
|
||||
|
||||
(self.asset1_md, self.asset2_md, self.asset3_md, self.asset4_md, self.asset5_md, self.asset6_md) = self.setup_assets()
|
||||
(self.thumb1_md, self.thumb2_md, self.thumb3_md, self.thumb4_md, self.thumb5_md, self.thumb6_md) = self.setup_thumbnails()
|
||||
|
||||
def tearDown(self):
|
||||
self.draft_store.delete_all_asset_metadata(self.course1.id)
|
||||
self.draft_store.delete_all_asset_metadata(self.course2.id)
|
||||
|
||||
def test_save_one_and_confirm(self):
|
||||
courses = self.draft_store.get_courses()
|
||||
course = courses[0]
|
||||
asset_filename = 'burnside.jpg'
|
||||
new_asset_loc = course.id.make_asset_key('asset', asset_filename)
|
||||
# Confirm that the asset's metadata is not present.
|
||||
self.assertIsNone(self.draft_store.find_asset_metadata(new_asset_loc))
|
||||
# Save the asset's metadata.
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(course.id, new_asset_md, 'John Doe'))
|
||||
# Find the asset's metadata and confirm it's the same.
|
||||
found_asset_md = self.draft_store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(found_asset_md)
|
||||
self.assertEquals(new_asset_md.asset_id, found_asset_md.asset_id)
|
||||
# Confirm that only two setup plus one asset's metadata exists.
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 3)
|
||||
# Delete all metadata and confirm it's gone.
|
||||
self.draft_store.delete_all_asset_metadata(course.id)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
def test_delete_all_without_creation(self):
|
||||
courses = self.draft_store.get_courses()
|
||||
course = courses[0]
|
||||
# Confirm that only setup asset metadata exists.
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 2)
|
||||
# Now delete the metadata.
|
||||
self.draft_store.delete_all_asset_metadata(course.id)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 0)
|
||||
# Now delete the non-existent metadata.
|
||||
self.draft_store.delete_all_asset_metadata(course.id)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
def test_save_many_and_delete_one(self):
|
||||
# Make sure there's two assets.
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(self.course1.id)), 2)
|
||||
# Delete one of the assets.
|
||||
self.assertEquals(self.draft_store.delete_asset_metadata(self.asset1_md.asset_id), 1)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(self.course1.id)), 1)
|
||||
# Attempt to delete an asset that doesn't exist.
|
||||
self.assertEquals(self.draft_store.delete_asset_metadata(self.asset5_md.asset_id), 0)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(self.course1.id)), 1)
|
||||
|
||||
def test_find_existing_and_non_existing_assets(self):
|
||||
# Find existing asset metadata.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(asset_md)
|
||||
# Find non-existent asset metadata.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset5_md.asset_id)
|
||||
self.assertIsNone(asset_md)
|
||||
|
||||
def test_add_same_asset_twice(self):
|
||||
courses = self.draft_store.get_courses()
|
||||
course = courses[0]
|
||||
asset_filename = 'burnside.jpg'
|
||||
new_asset_loc = course.id.make_asset_key('asset', asset_filename)
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
# Only the setup stuff here?
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 2)
|
||||
# Add asset metadata.
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(course.id, new_asset_md, "John Do"))
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 3)
|
||||
# Add *the same* asset metadata.
|
||||
self.assertTrue(self.draft_store.save_asset_metadata(course.id, new_asset_md, "John Dont"))
|
||||
# Still one here?
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 3)
|
||||
self.draft_store.delete_all_asset_metadata(course.id)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_metadata(course.id)), 0)
|
||||
|
||||
def test_lock_unlock_assets(self):
|
||||
# Find a course asset and check its locked status.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(asset_md)
|
||||
locked_state = asset_md.locked
|
||||
# Flip the course asset's locked status.
|
||||
self.draft_store.set_asset_metadata_attr(self.asset1_md.asset_id, "locked", not locked_state, 'John Doe')
|
||||
# Find the same course and check its locked status.
|
||||
updated_asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertEquals(updated_asset_md.locked, not locked_state)
|
||||
# Now flip it back.
|
||||
self.draft_store.set_asset_metadata_attr(self.asset1_md.asset_id, "locked", locked_state, 'John Doe')
|
||||
reupdated_asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(reupdated_asset_md)
|
||||
self.assertEquals(reupdated_asset_md.locked, locked_state)
|
||||
|
||||
ALLOWED_ATTRS = (
|
||||
('basename', '/new/path'),
|
||||
('internal_name', 'new_filename.txt'),
|
||||
('locked', True),
|
||||
('contenttype', 'image/png'),
|
||||
('md5', '5346682d948cc3f683635b6918f9b3d0'),
|
||||
('curr_version', 'v1.01'),
|
||||
('prev_version', 'v1.0'),
|
||||
('edited_by', 'Mork'),
|
||||
('edited_on', datetime(1969, 1, 1, tzinfo=UTC)),
|
||||
)
|
||||
|
||||
DISALLOWED_ATTRS = (
|
||||
('asset_id', 'IAmBogus'),
|
||||
)
|
||||
|
||||
UNKNOWN_ATTRS = (
|
||||
('lunch_order', 'burger_and_fries'),
|
||||
('villain', 'Khan')
|
||||
)
|
||||
|
||||
@data(*ALLOWED_ATTRS)
|
||||
def test_set_all_attrs(self, attr_pair):
|
||||
# Find a course asset.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(asset_md)
|
||||
# Set the course asset's attr.
|
||||
editing_user = 'user_who_edited'
|
||||
self.draft_store.set_asset_metadata_attr(self.asset1_md.asset_id, *attr_pair, user_id=editing_user)
|
||||
# Find the same course asset and check its changed attr.
|
||||
updated_asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attr_pair[0], None))
|
||||
if attr_pair[0] == 'edited_by':
|
||||
# No matter what the edited_by attr_pair is, it gets over-ridden by the passed-in user_id.
|
||||
self.assertEquals(getattr(updated_asset_md, attr_pair[0], None), editing_user)
|
||||
elif attr_pair[0] == 'edited_on':
|
||||
# edited_on is also over-ridden to be the time of update.
|
||||
pass
|
||||
else:
|
||||
self.assertEquals(getattr(updated_asset_md, attr_pair[0], None), attr_pair[1])
|
||||
|
||||
@data(*DISALLOWED_ATTRS)
|
||||
def test_set_disallowed_attrs(self, attr_pair):
|
||||
# Find a course asset.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(asset_md)
|
||||
original_attr_val = getattr(asset_md, attr_pair[0])
|
||||
# Set the course asset's attr.
|
||||
self.draft_store.set_asset_metadata_attr(self.asset1_md.asset_id, *attr_pair, user_id='John Doe')
|
||||
# Find the same course and check its changed attr.
|
||||
updated_asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attr_pair[0], None))
|
||||
# Make sure that the attr is unchanged from its original value.
|
||||
self.assertEquals(getattr(updated_asset_md, attr_pair[0], None), original_attr_val)
|
||||
|
||||
@data(*UNKNOWN_ATTRS)
|
||||
def test_set_unknown_attrs(self, attr_pair):
|
||||
# Find a course asset.
|
||||
asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(asset_md)
|
||||
# Set the course asset's attr.
|
||||
self.draft_store.set_asset_metadata_attr(self.asset1_md.asset_id, *attr_pair, user_id='John Smith')
|
||||
# Find the same course and check its changed attr.
|
||||
updated_asset_md = self.draft_store.find_asset_metadata(self.asset1_md.asset_id)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
# Make sure the unknown field was *not* added.
|
||||
with self.assertRaises(AttributeError):
|
||||
self.assertEquals(getattr(updated_asset_md, attr_pair[0]), attr_pair[1])
|
||||
|
||||
def test_save_one_thumbnail_and_delete_one_thumbnail(self):
|
||||
thumbnail_filename = 'burn_thumb.jpg'
|
||||
asset_key = self.course1.id.make_asset_key('thumbnail', thumbnail_filename)
|
||||
new_asset_thumbnail = self._make_asset_thumbnail_metadata(asset_key)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_thumbnail_metadata(self.course1.id)), 2)
|
||||
self.assertTrue(self.draft_store.save_asset_thumbnail_metadata(self.course1.id, new_asset_thumbnail))
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_thumbnail_metadata(self.course1.id)), 3)
|
||||
self.assertEquals(self.draft_store.delete_asset_thumbnail_metadata(asset_key), 1)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_thumbnail_metadata(self.course1.id)), 2)
|
||||
|
||||
def test_find_thumbnail(self):
|
||||
self.assertIsNotNone(self.draft_store.find_asset_thumbnail_metadata(self.thumb1_md.asset_id))
|
||||
self.assertIsNone(self.draft_store.find_asset_thumbnail_metadata(self.thumb5_md.asset_id))
|
||||
|
||||
def test_delete_all_thumbnails(self):
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_thumbnail_metadata(self.course1.id)), 2)
|
||||
self.draft_store.delete_all_asset_metadata(self.course1.id)
|
||||
self.assertEquals(len(self.draft_store.get_all_asset_thumbnail_metadata(self.course1.id)), 0)
|
||||
|
||||
def test_asset_object_equivalence(self):
|
||||
# Assets are only equivalent to themselves.
|
||||
self.assertTrue(self.asset6_md != self.thumb6_md)
|
||||
self.assertEquals(self.asset1_md, self.asset1_md)
|
||||
|
||||
def test_get_all_assets_with_paging(self):
|
||||
pass
|
||||
|
||||
def test_copy_all_assets(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore):
|
||||
'''
|
||||
Tests a situation where no asset_collection is specified.
|
||||
@@ -1017,7 +689,7 @@ class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore):
|
||||
# Confirm that no asset collection means no asset metadata.
|
||||
self.assertEquals(self.draft_store.get_all_asset_metadata(course.id), None)
|
||||
# Now delete the non-existent asset metadata.
|
||||
self.draft_store.delete_all_asset_metadata(course.id)
|
||||
self.draft_store.delete_all_asset_metadata(course.id, ModuleStoreEnum.UserID.test)
|
||||
# Should still be nothing.
|
||||
self.assertEquals(self.draft_store.get_all_asset_metadata(course.id), None)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user