def setUp(self): """ Set up module store testing capabilities and initialize test courses. """ super(CourseMetadataUtilsTestCase, self).setUp() mongo_builder = MongoModulestoreBuilder() split_builder = VersioningModulestoreBuilder() mixed_builder = MixedModulestoreBuilder([('mongo', mongo_builder), ('split', split_builder)]) with mixed_builder.build_without_contentstore() as (__, mixed_store): with mixed_store.default_store('mongo'): self.demo_course = mixed_store.create_course( org="edX", course="DemoX.1", run="Fall_2014", user_id=-3, # -3 refers to a "testing user" fields={ "start": _LAST_MONTH, "end": _LAST_WEEK } ) with mixed_store.default_store('split'): self.html_course = mixed_store.create_course( org="UniversityX", course="CS-203", run="Y2096", user_id=-3, # -3 refers to a "testing user" fields={ "start": _NEXT_WEEK, "display_name": "Intro to <html>" } )
from tempfile import mkdtemp from shutil import rmtree from unittest import TestCase, skip import ddt from django.test import TestCase from xmodule.modulestore.xml_importer import import_course_from_xml from xmodule.modulestore.xml_exporter import export_course_to_xml from xmodule.modulestore.tests.factories import check_mongo_calls from xmodule.modulestore.tests.utils import ( MixedModulestoreBuilder, VersioningModulestoreBuilder, MongoModulestoreBuilder, TEST_DATA_DIR, MemoryCache, ) MIXED_OLD_MONGO_MODULESTORE_BUILDER = MixedModulestoreBuilder([('draft', MongoModulestoreBuilder())]) MIXED_SPLIT_MODULESTORE_BUILDER = MixedModulestoreBuilder([('split', VersioningModulestoreBuilder())]) @ddt.ddt @skip("Fix call counts below - sometimes the counts are off by 1.") class CountMongoCallsXMLRoundtrip(TestCase): """ This class exists to test XML import and export to/from Split. """ shard = 2 def setUp(self): super(CountMongoCallsXMLRoundtrip, self).setUp() self.export_dir = mkdtemp() self.addCleanup(rmtree, self.export_dir, ignore_errors=True)
class TestMongoAssetMetadataStorage(TestCase): """ Tests for storing/querying course asset metadata. """ shard = 1 def setUp(self): super(TestMongoAssetMetadataStorage, self).setUp() self.addTypeEqualityFunc(datetime, self._compare_datetimes) self.addTypeEqualityFunc(AssetMetadata, self._compare_metadata) self.differents = (('different', 'burn.jpg'), ) self.vrmls = ( ('vrml', 'olympus_mons.vrml'), ('vrml', 'ponte_vecchio.vrml'), ) self.regular_assets = (('asset', 'zippy.png'), ) self.alls = self.differents + self.vrmls + self.regular_assets 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.ATTRS_ALLOWED_TO_UPDATE: 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. """ now = datetime.now(pytz.utc) return AssetMetadata( asset_loc, internal_name='EKMND332DDBK', pathname='pictures/historical', contenttype='image/jpeg', locked=False, fields={'md5': '77631ca4f0e08419b70726a447333ab6'}, edited_by=ModuleStoreEnum.UserID.test, edited_on=now, created_by=ModuleStoreEnum.UserID.test, created_on=now, curr_version='v1.0', prev_version='v0.95') def _make_asset_thumbnail_metadata(self, asset_md): """ Add thumbnail to the asset_md """ asset_md.thumbnail = 'ABC39XJUDN2' return asset_md def setup_assets(self, course1_key, course2_key, store=None): """ Setup assets. Save in store if given """ for i, asset in enumerate(AssetStoreTestData.all_asset_data): asset_dict = dict( zip(AssetStoreTestData.asset_fields[1:], asset[1:])) if i in (0, 1) and course1_key: asset_key = course1_key.make_asset_key('asset', asset[0]) asset_md = AssetMetadata(asset_key, **asset_dict) if store is not None: store.save_asset_metadata(asset_md, asset[4]) elif course2_key: asset_key = course2_key.make_asset_key('asset', asset[0]) asset_md = AssetMetadata(asset_key, **asset_dict) # Don't save assets 5 and 6. if store is not None and i not in (4, 5): store.save_asset_metadata(asset_md, asset[4]) @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 storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_filename = 'burnside.jpg' new_asset_loc = course.id.make_asset_key('asset', asset_filename) # Save the asset's metadata. new_asset_md = self._make_asset_metadata(new_asset_loc) store.save_asset_metadata(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) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'asset')), 1) @ddt.data(*MODULESTORE_SETUPS) def test_delete(self, storebuilder): """ Delete non-existent and existent metadata """ with storebuilder.build() 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, 'asset')), 0) new_asset_md = self._make_asset_metadata(new_asset_loc) store.save_asset_metadata(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, 'asset')), 0) @ddt.data(*MODULESTORE_SETUPS) def test_find_non_existing_assets(self, storebuilder): """ Find a non-existent asset in an existing course. """ with storebuilder.build() 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_get_all_non_existing_assets(self, storebuilder): """ Get all assets in an existing course when no assets exist. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Find existing asset metadata. asset_md = store.get_all_asset_metadata(course.id, 'asset') self.assertEquals(asset_md, []) @ddt.data(*MODULESTORE_SETUPS) def test_find_assets_in_non_existent_course(self, storebuilder): """ Find asset metadata from a non-existent course. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) fake_course_id = CourseKey.from_string( "{}nothere/{}nothere/{}nothere".format(course.id.org, course.id.course, course.id.run)) new_asset_loc = fake_course_id.make_asset_key( 'asset', 'burnside.jpg') # Find asset metadata from non-existent course. with self.assertRaises(ItemNotFoundError): store.find_asset_metadata(new_asset_loc) with self.assertRaises(ItemNotFoundError): store.get_all_asset_metadata(fake_course_id, 'asset') @ddt.data(*MODULESTORE_SETUPS) def test_add_same_asset_twice(self, storebuilder): """ Add an asset's metadata, then add it again. """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'asset')), 1) # Add *the same* asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) # Still one here? self.assertEquals( len(store.get_all_asset_metadata(course.id, 'asset')), 1) @ddt.data(*MODULESTORE_SETUPS) def test_different_asset_types(self, storebuilder): """ Test saving assets with other asset types. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) new_asset_loc = course.id.make_asset_key('vrml', 'pyramid.vrml') new_asset_md = self._make_asset_metadata(new_asset_loc) # Add asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'vrml')), 1) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'asset')), 0) @ddt.data(*MODULESTORE_SETUPS) def test_asset_types_with_other_field_names(self, storebuilder): """ Test saving assets using an asset type of 'course_id'. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) new_asset_loc = course.id.make_asset_key( 'course_id', 'just_to_see_if_it_still_works.jpg') new_asset_md = self._make_asset_metadata(new_asset_loc) # Add asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'course_id')), 1) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'asset')), 0) all_assets = store.get_all_asset_metadata(course.id, 'course_id') self.assertEquals(all_assets[0].asset_id.path, new_asset_loc.path) @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 storebuilder.build() 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(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 = ( ('pathname', '/new/path'), ('internal_name', 'new_filename.txt'), ('locked', True), ('contenttype', 'image/png'), ('thumbnail', 'new_filename_thumb.jpg'), ('fields', { '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'), ('created_by', 'Smith'), ('created_on', datetime.now(pytz.utc)), ) 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 storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.ALLOWED_ATTRS: # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course asset and check its changed attribute. updated_asset_md = store.find_asset_metadata(new_asset_loc) self.assertIsNotNone(updated_asset_md) self.assertIsNotNone(getattr(updated_asset_md, attribute, None)) self.assertEquals(getattr(updated_asset_md, attribute, None), value) @ddt.data(*MODULESTORE_SETUPS) def test_set_disallowed_attrs(self, storebuilder): """ setting disallowed attrs should fail """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.DISALLOWED_ATTRS: original_attr_val = getattr(new_asset_md, attribute) # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course and check its changed attribute. updated_asset_md = store.find_asset_metadata(new_asset_loc) self.assertIsNotNone(updated_asset_md) self.assertIsNotNone(getattr(updated_asset_md, attribute, None)) # Make sure that the attribute is unchanged from its original value. self.assertEquals(getattr(updated_asset_md, attribute, None), original_attr_val) @ddt.data(*MODULESTORE_SETUPS) def test_set_unknown_attrs(self, storebuilder): """ setting unknown attrs should fail """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.UNKNOWN_ATTRS: # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course and check its changed attribute. 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, attribute), value) @ddt.data(*MODULESTORE_SETUPS) def test_save_one_different_asset(self, storebuilder): """ saving and deleting things which are not 'asset' """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key)) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'different')), 1) self.assertEquals( store.delete_asset_metadata(asset_key, ModuleStoreEnum.UserID.test), 1) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'different')), 0) @ddt.data(*MODULESTORE_SETUPS) def test_find_different(self, storebuilder): """ finding things which are of type other than 'asset' """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key)) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) self.assertIsNotNone(store.find_asset_metadata(asset_key)) unknown_asset_key = course.id.make_asset_key( 'different', 'nosuchfile.jpg') self.assertIsNone(store.find_asset_metadata(unknown_asset_key)) def _check_asset_values(self, assets, orig): """ Check asset type/path values. """ for idx, asset in enumerate(orig): self.assertEquals(assets[idx].asset_id.asset_type, asset[0]) self.assertEquals(assets[idx].asset_id.path, asset[1]) @ddt.data(*MODULESTORE_SETUPS) def test_get_multiple_types(self, storebuilder): """ getting all things which are of type other than 'asset' """ # pylint: disable=bad-continuation with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Save 'em. for asset_type, filename in self.alls: asset_key = course.id.make_asset_key(asset_type, filename) new_asset = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key)) store.save_asset_metadata(new_asset, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ('asset', self.regular_assets), ): assets = store.get_all_asset_metadata(course.id, asset_type) self.assertEquals(len(assets), len(asset_list)) self._check_asset_values(assets, asset_list) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'not_here')), 0) self.assertEquals( len(store.get_all_asset_metadata(course.id, None)), 4) assets = store.get_all_asset_metadata( course.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(assets), len(self.alls)) self._check_asset_values(assets, self.alls) @ddt.data(*MODULESTORE_SETUPS) def test_save_metadata_list(self, storebuilder): """ Save a list of asset metadata all at once. """ # pylint: disable=bad-continuation with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Make a list of AssetMetadata objects. md_list = [] for asset_type, filename in self.alls: asset_key = course.id.make_asset_key(asset_type, filename) md_list.append( self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key))) # Save 'em. store.save_asset_metadata_list(md_list, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ('asset', self.regular_assets), ): assets = store.get_all_asset_metadata(course.id, asset_type) self.assertEquals(len(assets), len(asset_list)) self._check_asset_values(assets, asset_list) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'not_here')), 0) self.assertEquals( len(store.get_all_asset_metadata(course.id, None)), 4) assets = store.get_all_asset_metadata( course.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(assets), len(self.alls)) self._check_asset_values(assets, self.alls) @ddt.data(*MODULESTORE_SETUPS) def test_save_metadata_list_with_mismatched_asset(self, storebuilder): """ Save a list of asset metadata all at once - but with one asset's metadata from a different course. """ # pylint: disable=bad-continuation with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) # Make a list of AssetMetadata objects. md_list = [] for asset_type, filename in self.alls: if asset_type == 'asset': asset_key = course2.id.make_asset_key(asset_type, filename) else: asset_key = course1.id.make_asset_key(asset_type, filename) md_list.append( self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key))) # Save 'em. store.save_asset_metadata_list(md_list, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ): assets = store.get_all_asset_metadata(course1.id, asset_type) self.assertEquals(len(assets), len(asset_list)) self._check_asset_values(assets, asset_list) self.assertEquals( len(store.get_all_asset_metadata(course1.id, 'asset')), 0) self.assertEquals( len(store.get_all_asset_metadata(course1.id, None)), 3) assets = store.get_all_asset_metadata( course1.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(assets), len(self.differents + self.vrmls)) self._check_asset_values(assets, self.differents + self.vrmls) @ddt.data(*MODULESTORE_SETUPS) def test_delete_all_different_type(self, storebuilder): """ deleting all assets of a given but not 'asset' type """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn_thumb.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key)) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) self.assertEquals( len(store.get_all_asset_metadata(course.id, 'different')), 1) @ddt.data(*MODULESTORE_SETUPS) def test_get_all_assets_with_paging(self, storebuilder): """ Save multiple metadata in each store and retrieve it singularly, as all assets, and after deleting all. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) self.setup_assets(course1.id, course2.id, store) expected_sorts_by_2 = ( (('displayname', ModuleStoreEnum.SortOrder.ascending), ('code.tgz', 'demo.swf', 'dog.png', 'roman_history.pdf', 'weather_patterns.bmp'), (2, 2, 1)), (('displayname', ModuleStoreEnum.SortOrder.descending), ('weather_patterns.bmp', 'roman_history.pdf', 'dog.png', 'demo.swf', 'code.tgz'), (2, 2, 1)), (('uploadDate', ModuleStoreEnum.SortOrder.ascending), ('code.tgz', 'dog.png', 'roman_history.pdf', 'weather_patterns.bmp', 'demo.swf'), (2, 2, 1)), (('uploadDate', ModuleStoreEnum.SortOrder.descending), ('demo.swf', 'weather_patterns.bmp', 'roman_history.pdf', 'dog.png', 'code.tgz'), (2, 2, 1)), ) # First, with paging across all sorts. for sort_test in expected_sorts_by_2: for i in xrange(3): asset_page = store.get_all_asset_metadata( course2.id, 'asset', start=2 * i, maxresults=2, sort=sort_test[0]) num_expected_results = sort_test[2][i] expected_filename = sort_test[1][2 * i] self.assertEquals(len(asset_page), num_expected_results) self.assertEquals(asset_page[0].asset_id.path, expected_filename) if num_expected_results == 2: expected_filename = sort_test[1][(2 * i) + 1] self.assertEquals(asset_page[1].asset_id.path, expected_filename) # Now fetch everything. asset_page = store.get_all_asset_metadata( course2.id, 'asset', start=0, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(asset_page), 5) self.assertEquals(asset_page[0].asset_id.path, 'code.tgz') self.assertEquals(asset_page[1].asset_id.path, 'demo.swf') self.assertEquals(asset_page[2].asset_id.path, 'dog.png') self.assertEquals(asset_page[3].asset_id.path, 'roman_history.pdf') self.assertEquals(asset_page[4].asset_id.path, 'weather_patterns.bmp') # Some odd conditions. asset_page = store.get_all_asset_metadata( course2.id, 'asset', start=100, sort=('uploadDate', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(asset_page), 0) asset_page = store.get_all_asset_metadata( course2.id, 'asset', start=3, maxresults=0, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(asset_page), 0) asset_page = store.get_all_asset_metadata( course2.id, 'asset', start=3, maxresults=-12345, sort=('displayname', ModuleStoreEnum.SortOrder.descending)) self.assertEquals(len(asset_page), 2) @ddt.data(XmlModulestoreBuilder(), MixedModulestoreBuilder([('xml', XmlModulestoreBuilder())])) def test_xml_not_yet_implemented(self, storebuilder): """ Test coverage which shows that for now xml read operations are not implemented """ with storebuilder.build(contentstore=None) as (__, store): course_key = store.make_course_key("org", "course", "run") asset_key = course_key.make_asset_key('asset', 'foo.jpg') self.assertEquals(store.find_asset_metadata(asset_key), None) self.assertEquals( store.get_all_asset_metadata(course_key, 'asset'), []) @ddt.data(*MODULESTORE_SETUPS) def test_copy_all_assets_same_modulestore(self, storebuilder): """ Create a course with assets, copy them all to another course in the same modulestore, and check on it. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) self.setup_assets(course1.id, None, store) self.assertEquals( len(store.get_all_asset_metadata(course1.id, 'asset')), 2) self.assertEquals( len(store.get_all_asset_metadata(course2.id, 'asset')), 0) store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101) self.assertEquals( len(store.get_all_asset_metadata(course1.id, 'asset')), 2) all_assets = store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(all_assets), 2) self.assertEquals(all_assets[0].asset_id.path, 'pic1.jpg') self.assertEquals(all_assets[1].asset_id.path, 'shout.ogg') @ddt.data(*MODULESTORE_SETUPS) def test_copy_all_assets_from_course_with_no_assets(self, storebuilder): """ Create a course with *no* assets, and try copy them all to another course in the same modulestore. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101) self.assertEquals( len(store.get_all_asset_metadata(course1.id, 'asset')), 0) self.assertEquals( len(store.get_all_asset_metadata(course2.id, 'asset')), 0) all_assets = store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(all_assets), 0) @ddt.data( ('mongo', 'split'), ('split', 'mongo'), ) @ddt.unpack def test_copy_all_assets_cross_modulestore(self, from_store, to_store): """ Create a course with assets, copy them all to another course in a different modulestore, and check on it. """ mixed_builder = MIXED_MODULESTORE_BOTH_SETUP with mixed_builder.build() as (__, mixed_store): with mixed_store.default_store(from_store): course1 = CourseFactory.create(modulestore=mixed_store) with mixed_store.default_store(to_store): course2 = CourseFactory.create(modulestore=mixed_store) self.setup_assets(course1.id, None, mixed_store) self.assertEquals( len(mixed_store.get_all_asset_metadata(course1.id, 'asset')), 2) self.assertEquals( len(mixed_store.get_all_asset_metadata(course2.id, 'asset')), 0) mixed_store.copy_all_asset_metadata( course1.id, course2.id, ModuleStoreEnum.UserID.test * 102) all_assets = mixed_store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)) self.assertEquals(len(all_assets), 2) self.assertEquals(all_assets[0].asset_id.path, 'pic1.jpg') self.assertEquals(all_assets[1].asset_id.path, 'shout.ogg')
class TestMongoAssetMetadataStorage(TestCase): """ Tests for storing/querying course asset metadata. """ XML_MODULESTORE_MAP = { 'XML_MODULESTORE_BUILDER': XmlModulestoreBuilder(), 'MIXED_MODULESTORE_BUILDER': MixedModulestoreBuilder([('xml', XmlModulestoreBuilder())]) } def setUp(self): super().setUp() self.differents = (('different', 'burn.jpg'),) self.vrmls = ( ('vrml', 'olympus_mons.vrml'), ('vrml', 'ponte_vecchio.vrml'), ) self.regular_assets = (('asset', 'zippy.png'),) self.alls = self.differents + self.vrmls + self.regular_assets def _assert_metadata_equal(self, mdata1, mdata2): """ So we can use the below date comparison """ for attr in mdata1.ATTRS_ALLOWED_TO_UPDATE: # lint-amnesty, pylint: disable=redefined-outer-name if isinstance(getattr(mdata1, attr), datetime): self._assert_datetimes_equal(getattr(mdata1, attr), getattr(mdata2, attr)) else: assert getattr(mdata1, attr) == getattr(mdata2, attr) def _assert_datetimes_equal(self, datetime1, datetime2): """ Don't compare microseconds as mongo doesn't encode below milliseconds """ assert datetime1.replace(microsecond=0) == datetime2.replace(microsecond=0) def _make_asset_metadata(self, asset_loc): """ Make a single test asset metadata. """ now = datetime.now(pytz.utc) return AssetMetadata( asset_loc, internal_name='EKMND332DDBK', pathname='pictures/historical', contenttype='image/jpeg', locked=False, fields={'md5': '77631ca4f0e08419b70726a447333ab6'}, edited_by=ModuleStoreEnum.UserID.test, edited_on=now, created_by=ModuleStoreEnum.UserID.test, created_on=now, curr_version='v1.0', prev_version='v0.95' ) def _make_asset_thumbnail_metadata(self, asset_md): """ Add thumbnail to the asset_md """ asset_md.thumbnail = 'ABC39XJUDN2' return asset_md def setup_assets(self, course1_key, course2_key, store=None): """ Setup assets. Save in store if given """ for i, asset in enumerate(AssetStoreTestData.all_asset_data): asset_dict = dict(list(zip(AssetStoreTestData.asset_fields[1:], asset[1:]))) if i in (0, 1) and course1_key: asset_key = course1_key.make_asset_key('asset', asset[0]) asset_md = AssetMetadata(asset_key, **asset_dict) if store is not None: store.save_asset_metadata(asset_md, asset[4]) elif course2_key: asset_key = course2_key.make_asset_key('asset', asset[0]) asset_md = AssetMetadata(asset_key, **asset_dict) # Don't save assets 5 and 6. if store is not None and i not in (4, 5): store.save_asset_metadata(asset_md, asset[4]) @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 storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_filename = 'burnside.jpg' new_asset_loc = course.id.make_asset_key('asset', asset_filename) # Save the asset's metadata. new_asset_md = self._make_asset_metadata(new_asset_loc) store.save_asset_metadata(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) assert found_asset_md is not None self._assert_metadata_equal(new_asset_md, found_asset_md) assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1 @ddt.data(*MODULESTORE_SETUPS) def test_delete(self, storebuilder): """ Delete non-existent and existent metadata """ with storebuilder.build() 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. assert store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test) == 0 assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0 new_asset_md = self._make_asset_metadata(new_asset_loc) store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) assert store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test) == 1 assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0 @ddt.data(*MODULESTORE_SETUPS) def test_find_non_existing_assets(self, storebuilder): """ Find a non-existent asset in an existing course. """ with storebuilder.build() 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) assert asset_md is None @ddt.data(*MODULESTORE_SETUPS) def test_get_all_non_existing_assets(self, storebuilder): """ Get all assets in an existing course when no assets exist. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Find existing asset metadata. asset_md = store.get_all_asset_metadata(course.id, 'asset') assert asset_md == [] @ddt.data(*MODULESTORE_SETUPS) def test_find_assets_in_non_existent_course(self, storebuilder): """ Find asset metadata from a non-existent course. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) fake_course_id = CourseKey.from_string("{}nothere/{}nothere/{}nothere".format( course.id.org, course.id.course, course.id.run )) new_asset_loc = fake_course_id.make_asset_key('asset', 'burnside.jpg') # Find asset metadata from non-existent course. with pytest.raises(ItemNotFoundError): store.find_asset_metadata(new_asset_loc) with pytest.raises(ItemNotFoundError): store.get_all_asset_metadata(fake_course_id, 'asset') @ddt.data(*MODULESTORE_SETUPS) def test_add_same_asset_twice(self, storebuilder): """ Add an asset's metadata, then add it again. """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1 # Add *the same* asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) # Still one here? assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1 @ddt.data(*MODULESTORE_SETUPS) def test_different_asset_types(self, storebuilder): """ Test saving assets with other asset types. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) new_asset_loc = course.id.make_asset_key('vrml', 'pyramid.vrml') new_asset_md = self._make_asset_metadata(new_asset_loc) # Add asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) assert len(store.get_all_asset_metadata(course.id, 'vrml')) == 1 assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0 @ddt.data(*MODULESTORE_SETUPS) def test_asset_types_with_other_field_names(self, storebuilder): """ Test saving assets using an asset type of 'course_id'. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) new_asset_loc = course.id.make_asset_key('course_id', 'just_to_see_if_it_still_works.jpg') new_asset_md = self._make_asset_metadata(new_asset_loc) # Add asset metadata. store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test) assert len(store.get_all_asset_metadata(course.id, 'course_id')) == 1 assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0 all_assets = store.get_all_asset_metadata(course.id, 'course_id') assert all_assets[0].asset_id.path == new_asset_loc.path @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 storebuilder.build() 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(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) assert updated_asset_md is not None assert 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) assert reupdated_asset_md is not None assert reupdated_asset_md.locked == locked_state ALLOWED_ATTRS = ( ('pathname', '/new/path'), ('internal_name', 'new_filename.txt'), ('locked', True), ('contenttype', 'image/png'), ('thumbnail', 'new_filename_thumb.jpg'), ('fields', {'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'), ('created_by', 'Smith'), ('created_on', datetime.now(pytz.utc)), ) 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 storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.ALLOWED_ATTRS: # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course asset and check its changed attribute. updated_asset_md = store.find_asset_metadata(new_asset_loc) assert updated_asset_md is not None assert getattr(updated_asset_md, attribute, None) is not None assert getattr(updated_asset_md, attribute, None) == value @ddt.data(*MODULESTORE_SETUPS) def test_set_disallowed_attrs(self, storebuilder): """ setting disallowed attrs should fail """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.DISALLOWED_ATTRS: original_attr_val = getattr(new_asset_md, attribute) # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course and check its changed attribute. updated_asset_md = store.find_asset_metadata(new_asset_loc) assert updated_asset_md is not None updated_attr_val = getattr(updated_asset_md, attribute, None) assert updated_attr_val is not None # Make sure that the attribute is unchanged from its original value. if isinstance(original_attr_val, datetime): self._assert_datetimes_equal(updated_attr_val, original_attr_val) else: assert updated_attr_val == original_attr_val @ddt.data(*MODULESTORE_SETUPS) def test_set_unknown_attrs(self, storebuilder): """ setting unknown attrs should fail """ with storebuilder.build() 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(new_asset_md, ModuleStoreEnum.UserID.test) for attribute, value in self.UNKNOWN_ATTRS: # Set the course asset's attribute. store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test) # Find the same course and check its changed attribute. updated_asset_md = store.find_asset_metadata(new_asset_loc) assert updated_asset_md is not None # Make sure the unknown field was *not* added. with pytest.raises(AttributeError): assert getattr(updated_asset_md, attribute) == value @ddt.data(*MODULESTORE_SETUPS) def test_save_one_different_asset(self, storebuilder): """ saving and deleting things which are not 'asset' """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) ) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) assert len(store.get_all_asset_metadata(course.id, 'different')) == 1 assert store.delete_asset_metadata(asset_key, ModuleStoreEnum.UserID.test) == 1 assert len(store.get_all_asset_metadata(course.id, 'different')) == 0 @ddt.data(*MODULESTORE_SETUPS) def test_find_different(self, storebuilder): """ finding things which are of type other than 'asset' """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) ) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) assert store.find_asset_metadata(asset_key) is not None unknown_asset_key = course.id.make_asset_key('different', 'nosuchfile.jpg') assert store.find_asset_metadata(unknown_asset_key) is None def _check_asset_values(self, assets, orig): """ Check asset type/path values. """ for idx, asset in enumerate(orig): assert assets[idx].asset_id.asset_type == asset[0] assert assets[idx].asset_id.path == asset[1] @ddt.data(*MODULESTORE_SETUPS) def test_get_multiple_types(self, storebuilder): """ getting all things which are of type other than 'asset' """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Save 'em. for asset_type, filename in self.alls: asset_key = course.id.make_asset_key(asset_type, filename) new_asset = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) ) store.save_asset_metadata(new_asset, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ('asset', self.regular_assets), ): assets = store.get_all_asset_metadata(course.id, asset_type) assert len(assets) == len(asset_list) self._check_asset_values(assets, asset_list) assert len(store.get_all_asset_metadata(course.id, 'not_here')) == 0 assert len(store.get_all_asset_metadata(course.id, None)) == 4 assets = store.get_all_asset_metadata( course.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(assets) == len(self.alls) self._check_asset_values(assets, self.alls) @ddt.data(*MODULESTORE_SETUPS) def test_save_metadata_list(self, storebuilder): """ Save a list of asset metadata all at once. """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) # Make a list of AssetMetadata objects. md_list = [] for asset_type, filename in self.alls: asset_key = course.id.make_asset_key(asset_type, filename) md_list.append(self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) )) # Save 'em. store.save_asset_metadata_list(md_list, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ('asset', self.regular_assets), ): assets = store.get_all_asset_metadata(course.id, asset_type) assert len(assets) == len(asset_list) self._check_asset_values(assets, asset_list) assert len(store.get_all_asset_metadata(course.id, 'not_here')) == 0 assert len(store.get_all_asset_metadata(course.id, None)) == 4 assets = store.get_all_asset_metadata( course.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(assets) == len(self.alls) self._check_asset_values(assets, self.alls) @ddt.data(*MODULESTORE_SETUPS) def test_save_metadata_list_with_mismatched_asset(self, storebuilder): """ Save a list of asset metadata all at once - but with one asset's metadata from a different course. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) # Make a list of AssetMetadata objects. md_list = [] for asset_type, filename in self.alls: if asset_type == 'asset': asset_key = course2.id.make_asset_key(asset_type, filename) else: asset_key = course1.id.make_asset_key(asset_type, filename) md_list.append(self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) )) # Save 'em. store.save_asset_metadata_list(md_list, ModuleStoreEnum.UserID.test) # Check 'em. for asset_type, asset_list in ( ('different', self.differents), ('vrml', self.vrmls), ): assets = store.get_all_asset_metadata(course1.id, asset_type) assert len(assets) == len(asset_list) self._check_asset_values(assets, asset_list) assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 0 assert len(store.get_all_asset_metadata(course1.id, None)) == 3 assets = store.get_all_asset_metadata( course1.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(assets) == len(self.differents + self.vrmls) self._check_asset_values(assets, self.differents + self.vrmls) @ddt.data(*MODULESTORE_SETUPS) def test_delete_all_different_type(self, storebuilder): """ deleting all assets of a given but not 'asset' type """ with storebuilder.build() as (__, store): course = CourseFactory.create(modulestore=store) asset_key = course.id.make_asset_key('different', 'burn_thumb.jpg') new_asset_thumbnail = self._make_asset_thumbnail_metadata( self._make_asset_metadata(asset_key) ) store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test) assert len(store.get_all_asset_metadata(course.id, 'different')) == 1 @ddt.data('XML_MODULESTORE_BUILDER', 'MIXED_MODULESTORE_BUILDER') def test_xml_not_yet_implemented(self, storebuilderName): """ Test coverage which shows that for now xml read operations are not implemented """ storebuilder = self.XML_MODULESTORE_MAP[storebuilderName] with storebuilder.build(contentstore=None) as (__, store): course_key = store.make_course_key("org", "course", "run") asset_key = course_key.make_asset_key('asset', 'foo.jpg') assert store.find_asset_metadata(asset_key) is None assert store.get_all_asset_metadata(course_key, 'asset') == [] @ddt.data(*MODULESTORE_SETUPS) def test_copy_all_assets_same_modulestore(self, storebuilder): """ Create a course with assets, copy them all to another course in the same modulestore, and check on it. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) self.setup_assets(course1.id, None, store) assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 2 assert len(store.get_all_asset_metadata(course2.id, 'asset')) == 0 store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101) assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 2 all_assets = store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(all_assets) == 2 assert all_assets[0].asset_id.path == 'pic1.jpg' assert all_assets[1].asset_id.path == 'shout.ogg' @ddt.data(*MODULESTORE_SETUPS) def test_copy_all_assets_from_course_with_no_assets(self, storebuilder): """ Create a course with *no* assets, and try copy them all to another course in the same modulestore. """ with storebuilder.build() as (__, store): course1 = CourseFactory.create(modulestore=store) course2 = CourseFactory.create(modulestore=store) store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101) assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 0 assert len(store.get_all_asset_metadata(course2.id, 'asset')) == 0 all_assets = store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(all_assets) == 0 @ddt.data( ('mongo', 'split'), ('split', 'mongo'), ) @ddt.unpack def test_copy_all_assets_cross_modulestore(self, from_store, to_store): """ Create a course with assets, copy them all to another course in a different modulestore, and check on it. """ mixed_builder = MIXED_MODULESTORE_BOTH_SETUP with mixed_builder.build() as (__, mixed_store): with mixed_store.default_store(from_store): course1 = CourseFactory.create(modulestore=mixed_store) with mixed_store.default_store(to_store): course2 = CourseFactory.create(modulestore=mixed_store) self.setup_assets(course1.id, None, mixed_store) assert len(mixed_store.get_all_asset_metadata(course1.id, 'asset')) == 2 assert len(mixed_store.get_all_asset_metadata(course2.id, 'asset')) == 0 mixed_store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 102) all_assets = mixed_store.get_all_asset_metadata( course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) assert len(all_assets) == 2 assert all_assets[0].asset_id.path == 'pic1.jpg' assert all_assets[1].asset_id.path == 'shout.ogg'