/common/lib/xmodule/xmodule/modulestore/tests/test_modulestore_settings.py

https://gitlab.com/unofficial-mirrors/edx-platform
Python | 207 lines | 160 code | 22 blank | 25 comment | 10 complexity | ba2f4995455a33010b4e1ab7ebbe024e MD5 | raw file
  1. """
  2. Tests for testing the modulestore settings migration code.
  3. """
  4. import copy
  5. import ddt
  6. from openedx.core.lib.tempdir import mkdtemp_clean
  7. from unittest import TestCase
  8. from xmodule.modulestore.modulestore_settings import (
  9. convert_module_store_setting_if_needed,
  10. update_module_store_settings,
  11. get_mixed_stores,
  12. )
  13. @ddt.ddt
  14. class ModuleStoreSettingsMigration(TestCase):
  15. """
  16. Tests for the migration code for the module store settings
  17. """
  18. OLD_CONFIG = {
  19. "default": {
  20. "ENGINE": "xmodule.modulestore.xml.XMLModuleStore",
  21. "OPTIONS": {
  22. "data_dir": "directory",
  23. "default_class": "xmodule.hidden_module.HiddenDescriptor",
  24. },
  25. "DOC_STORE_CONFIG": {},
  26. }
  27. }
  28. OLD_CONFIG_WITH_DIRECT_MONGO = {
  29. "default": {
  30. "ENGINE": "xmodule.modulestore.mongo.MongoModuleStore",
  31. "OPTIONS": {
  32. "collection": "modulestore",
  33. "db": "edxapp",
  34. "default_class": "xmodule.hidden_module.HiddenDescriptor",
  35. "fs_root": mkdtemp_clean(),
  36. "host": "localhost",
  37. "password": "password",
  38. "port": 27017,
  39. "render_template": "edxmako.shortcuts.render_to_string",
  40. "user": "edxapp"
  41. },
  42. "DOC_STORE_CONFIG": {},
  43. }
  44. }
  45. OLD_MIXED_CONFIG_WITH_DICT = {
  46. "default": {
  47. "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore",
  48. "OPTIONS": {
  49. "mappings": {},
  50. "stores": {
  51. "an_old_mongo_store": {
  52. "DOC_STORE_CONFIG": {},
  53. "ENGINE": "xmodule.modulestore.mongo.MongoModuleStore",
  54. "OPTIONS": {
  55. "collection": "modulestore",
  56. "db": "test",
  57. "default_class": "xmodule.hidden_module.HiddenDescriptor",
  58. }
  59. },
  60. "default": {
  61. "ENGINE": "the_default_store",
  62. "OPTIONS": {
  63. "option1": "value1",
  64. "option2": "value2"
  65. },
  66. "DOC_STORE_CONFIG": {}
  67. },
  68. "xml": {
  69. "ENGINE": "xmodule.modulestore.xml.XMLModuleStore",
  70. "OPTIONS": {
  71. "data_dir": "directory",
  72. "default_class": "xmodule.hidden_module.HiddenDescriptor"
  73. },
  74. "DOC_STORE_CONFIG": {}
  75. }
  76. }
  77. }
  78. }
  79. }
  80. ALREADY_UPDATED_MIXED_CONFIG = {
  81. 'default': {
  82. 'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
  83. 'OPTIONS': {
  84. 'mappings': {},
  85. 'stores': [
  86. {
  87. 'NAME': 'split',
  88. 'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
  89. 'DOC_STORE_CONFIG': {},
  90. 'OPTIONS': {
  91. 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
  92. 'fs_root': "fs_root",
  93. 'render_template': 'edxmako.shortcuts.render_to_string',
  94. }
  95. },
  96. {
  97. 'NAME': 'draft',
  98. 'ENGINE': 'xmodule.modulestore.mongo.draft.DraftModuleStore',
  99. 'DOC_STORE_CONFIG': {},
  100. 'OPTIONS': {
  101. 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
  102. 'fs_root': "fs_root",
  103. 'render_template': 'edxmako.shortcuts.render_to_string',
  104. }
  105. },
  106. ]
  107. }
  108. }
  109. }
  110. def assertStoreValuesEqual(self, store_setting1, store_setting2):
  111. """
  112. Tests whether the fields in the given store_settings are equal.
  113. """
  114. store_fields = ["OPTIONS", "DOC_STORE_CONFIG"]
  115. for field in store_fields:
  116. self.assertEqual(store_setting1[field], store_setting2[field])
  117. def assertMigrated(self, old_setting):
  118. """
  119. Migrates the given setting and checks whether it correctly converted
  120. to an ordered list of stores within Mixed.
  121. """
  122. # pass a copy of the old setting since the migration modifies the given setting
  123. new_mixed_setting = convert_module_store_setting_if_needed(copy.deepcopy(old_setting))
  124. # check whether the configuration is encapsulated within Mixed.
  125. self.assertEqual(new_mixed_setting["default"]["ENGINE"], "xmodule.modulestore.mixed.MixedModuleStore")
  126. # check whether the stores are in an ordered list
  127. new_stores = get_mixed_stores(new_mixed_setting)
  128. self.assertIsInstance(new_stores, list)
  129. return new_mixed_setting, new_stores[0]
  130. def is_split_configured(self, mixed_setting):
  131. """
  132. Tests whether the split module store is configured in the given setting.
  133. """
  134. stores = get_mixed_stores(mixed_setting)
  135. split_settings = [store for store in stores if store['ENGINE'].endswith('.DraftVersioningModuleStore')]
  136. if len(split_settings):
  137. # there should only be one setting for split
  138. self.assertEquals(len(split_settings), 1)
  139. # verify name
  140. self.assertEquals(split_settings[0]['NAME'], 'split')
  141. # verify split config settings equal those of mongo
  142. self.assertStoreValuesEqual(
  143. split_settings[0],
  144. next((store for store in stores if 'DraftModuleStore' in store['ENGINE']), None)
  145. )
  146. return len(split_settings) > 0
  147. def test_convert_into_mixed(self):
  148. old_setting = self.OLD_CONFIG
  149. new_mixed_setting, new_default_store_setting = self.assertMigrated(old_setting)
  150. self.assertStoreValuesEqual(new_default_store_setting, old_setting["default"])
  151. self.assertEqual(new_default_store_setting["ENGINE"], old_setting["default"]["ENGINE"])
  152. self.assertFalse(self.is_split_configured(new_mixed_setting))
  153. def test_convert_from_old_mongo_to_draft_store(self):
  154. old_setting = self.OLD_CONFIG_WITH_DIRECT_MONGO
  155. new_mixed_setting, new_default_store_setting = self.assertMigrated(old_setting)
  156. self.assertStoreValuesEqual(new_default_store_setting, old_setting["default"])
  157. self.assertEqual(new_default_store_setting["ENGINE"], "xmodule.modulestore.mongo.draft.DraftModuleStore")
  158. self.assertTrue(self.is_split_configured(new_mixed_setting))
  159. def test_convert_from_dict_to_list(self):
  160. old_mixed_setting = self.OLD_MIXED_CONFIG_WITH_DICT
  161. new_mixed_setting, new_default_store_setting = self.assertMigrated(old_mixed_setting)
  162. self.assertEqual(new_default_store_setting["ENGINE"], "the_default_store")
  163. self.assertTrue(self.is_split_configured(new_mixed_setting))
  164. # exclude split when comparing old and new, since split was added as part of the migration
  165. new_stores = [store for store in get_mixed_stores(new_mixed_setting) if store['NAME'] != 'split']
  166. old_stores = get_mixed_stores(self.OLD_MIXED_CONFIG_WITH_DICT)
  167. # compare each store configured in mixed
  168. self.assertEqual(len(new_stores), len(old_stores))
  169. for new_store in new_stores:
  170. self.assertStoreValuesEqual(new_store, old_stores[new_store['NAME']])
  171. def test_no_conversion(self):
  172. # make sure there is no migration done on an already updated config
  173. old_mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
  174. new_mixed_setting, new_default_store_setting = self.assertMigrated(old_mixed_setting)
  175. self.assertTrue(self.is_split_configured(new_mixed_setting))
  176. self.assertEquals(old_mixed_setting, new_mixed_setting)
  177. @ddt.data('draft', 'split')
  178. def test_update_settings(self, default_store):
  179. mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
  180. update_module_store_settings(mixed_setting, default_store=default_store)
  181. self.assertEqual(get_mixed_stores(mixed_setting)[0]['NAME'], default_store)
  182. def test_update_settings_error(self):
  183. mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
  184. with self.assertRaises(Exception):
  185. update_module_store_settings(mixed_setting, default_store='non-existent store')