You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_loading.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. from os.path import dirname
  2. import sys
  3. from django.test import override_settings, TestCase
  4. from django.conf import settings
  5. import oscar
  6. from oscar.core.loading import (
  7. get_model, AppNotFoundError, get_classes, get_class, get_class_loader,
  8. ClassNotFoundError)
  9. from oscar.test.factories import create_product, WishListFactory, UserFactory
  10. from tests import temporary_python_path
  11. from tests._site.loader import DummyClass
  12. class TestClassLoading(TestCase):
  13. """
  14. Oscar's class loading utilities
  15. """
  16. def test_load_oscar_classes_correctly(self):
  17. Product, Category = get_classes('catalogue.models', ('Product', 'Category'))
  18. self.assertEqual('oscar.apps.catalogue.models', Product.__module__)
  19. self.assertEqual('oscar.apps.catalogue.models', Category.__module__)
  20. def test_load_oscar_class_correctly(self):
  21. Product = get_class('catalogue.models', 'Product')
  22. self.assertEqual('oscar.apps.catalogue.models', Product.__module__)
  23. def test_load_oscar_class_from_dashboard_subapp(self):
  24. ReportForm = get_class('dashboard.reports.forms', 'ReportForm')
  25. self.assertEqual('oscar.apps.dashboard.reports.forms', ReportForm.__module__)
  26. def test_raise_exception_when_bad_appname_used(self):
  27. with self.assertRaises(AppNotFoundError):
  28. get_classes('fridge.models', ('Product', 'Category'))
  29. def test_raise_exception_when_bad_classname_used(self):
  30. with self.assertRaises(ClassNotFoundError):
  31. get_class('catalogue.models', 'Monkey')
  32. def test_raise_importerror_if_app_raises_importerror(self):
  33. """
  34. This tests that Oscar doesn't fall back to using the Oscar catalogue
  35. app if the overriding app throws an ImportError.
  36. """
  37. apps = list(settings.INSTALLED_APPS)
  38. apps[apps.index('oscar.apps.catalogue')] = 'tests._site.import_error_app.catalogue'
  39. with override_settings(INSTALLED_APPS=apps):
  40. with self.assertRaises(ImportError):
  41. get_class('catalogue.app', 'CatalogueApplication')
  42. class ClassLoadingWithLocalOverrideTests(TestCase):
  43. def setUp(self):
  44. self.installed_apps = list(settings.INSTALLED_APPS)
  45. self.installed_apps[self.installed_apps.index('oscar.apps.shipping')] = 'tests._site.shipping'
  46. def test_loading_class_defined_in_local_module(self):
  47. with override_settings(INSTALLED_APPS=self.installed_apps):
  48. (Free,) = get_classes('shipping.methods', ('Free',))
  49. self.assertEqual('tests._site.shipping.methods', Free.__module__)
  50. def test_loading_class_which_is_not_defined_in_local_module(self):
  51. with override_settings(INSTALLED_APPS=self.installed_apps):
  52. (FixedPrice,) = get_classes('shipping.methods', ('FixedPrice',))
  53. self.assertEqual('oscar.apps.shipping.methods', FixedPrice.__module__)
  54. def test_loading_class_from_module_not_defined_in_local_app(self):
  55. with override_settings(INSTALLED_APPS=self.installed_apps):
  56. (Repository,) = get_classes('shipping.repository', ('Repository',))
  57. self.assertEqual('oscar.apps.shipping.repository', Repository.__module__)
  58. def test_loading_classes_defined_in_both_local_and_oscar_modules(self):
  59. with override_settings(INSTALLED_APPS=self.installed_apps):
  60. (Free, FixedPrice) = get_classes('shipping.methods', ('Free', 'FixedPrice'))
  61. self.assertEqual('tests._site.shipping.methods', Free.__module__)
  62. self.assertEqual('oscar.apps.shipping.methods', FixedPrice.__module__)
  63. def test_loading_classes_with_root_app(self):
  64. import tests._site.shipping
  65. path = dirname(dirname(tests._site.shipping.__file__))
  66. with temporary_python_path([path]):
  67. self.installed_apps[
  68. self.installed_apps.index('tests._site.shipping')] = 'shipping'
  69. with override_settings(INSTALLED_APPS=self.installed_apps):
  70. (Free,) = get_classes('shipping.methods', ('Free',))
  71. self.assertEqual('shipping.methods', Free.__module__)
  72. def test_overriding_view_is_possible_without_overriding_app(self):
  73. from oscar.apps.customer.app import application, CustomerApplication
  74. # If test fails, it's helpful to know if it's caused by order of
  75. # execution
  76. self.assertEqual(CustomerApplication().summary_view.__module__,
  77. 'tests._site.apps.customer.views')
  78. self.assertEqual(application.summary_view.__module__,
  79. 'tests._site.apps.customer.views')
  80. class ClassLoadingWithLocalOverrideWithMultipleSegmentsTests(TestCase):
  81. def setUp(self):
  82. self.installed_apps = list(settings.INSTALLED_APPS)
  83. self.installed_apps[self.installed_apps.index('oscar.apps.shipping')] = 'tests._site.apps.shipping'
  84. def test_loading_class_defined_in_local_module(self):
  85. with override_settings(INSTALLED_APPS=self.installed_apps):
  86. (Free,) = get_classes('shipping.methods', ('Free',))
  87. self.assertEqual('tests._site.apps.shipping.methods', Free.__module__)
  88. class TestGetCoreAppsFunction(TestCase):
  89. """
  90. oscar.get_core_apps function
  91. """
  92. def test_returns_core_apps_when_no_overrides_specified(self):
  93. apps = oscar.get_core_apps()
  94. self.assertEqual(oscar.OSCAR_CORE_APPS, apps)
  95. def test_uses_non_dashboard_override_when_specified(self):
  96. apps = oscar.get_core_apps(overrides=['apps.shipping'])
  97. self.assertTrue('apps.shipping' in apps)
  98. self.assertTrue('oscar.apps.shipping' not in apps)
  99. def test_uses_dashboard_override_when_specified(self):
  100. apps = oscar.get_core_apps(overrides=['apps.dashboard.catalogue'])
  101. self.assertTrue('apps.dashboard.catalogue' in apps)
  102. self.assertTrue('oscar.apps.dashboard.catalogue' not in apps)
  103. self.assertTrue('oscar.apps.catalogue' in apps)
  104. class TestOverridingCoreApps(TestCase):
  105. def test_means_the_overriding_model_is_registered_first(self):
  106. klass = get_model('partner', 'StockRecord')
  107. self.assertEqual(
  108. 'tests._site.apps.partner.models', klass.__module__)
  109. class TestAppLabelsForModels(TestCase):
  110. def test_all_oscar_models_have_app_labels(self):
  111. from django.apps import apps
  112. models = apps.get_models()
  113. missing = []
  114. for model in models:
  115. # Ignore non-Oscar models
  116. if 'oscar' not in repr(model):
  117. continue
  118. # Don't know how to get the actual model's Meta class. But if
  119. # the parent doesn't have a Meta class, it's doesn't have an
  120. # base in Oscar anyway and is not intended to be overridden
  121. abstract_model = model.__base__
  122. meta_class = getattr(abstract_model, 'Meta', None)
  123. if meta_class is None:
  124. continue
  125. if not hasattr(meta_class, 'app_label'):
  126. missing.append(model)
  127. if missing:
  128. self.fail("Those models don't have an app_label set: %s" % missing)
  129. class TestDynamicLoadingOn3rdPartyApps(TestCase):
  130. core_app_prefix = 'thirdparty_package.apps'
  131. def setUp(self):
  132. self.installed_apps = list(settings.INSTALLED_APPS)
  133. sys.path.append('./tests/_site/')
  134. def tearDown(self):
  135. sys.path.remove('./tests/_site/')
  136. def test_load_core_3rd_party_class_correctly(self):
  137. self.installed_apps.append('thirdparty_package.apps.myapp')
  138. with override_settings(INSTALLED_APPS=self.installed_apps):
  139. Cow, Goat = get_classes('myapp.models', ('Cow', 'Goat'), self.core_app_prefix)
  140. self.assertEqual('thirdparty_package.apps.myapp.models', Cow.__module__)
  141. self.assertEqual('thirdparty_package.apps.myapp.models', Goat.__module__)
  142. def test_load_overriden_3rd_party_class_correctly(self):
  143. self.installed_apps.append('apps.myapp')
  144. with override_settings(INSTALLED_APPS=self.installed_apps):
  145. Cow, Goat = get_classes('myapp.models', ('Cow', 'Goat'), self.core_app_prefix)
  146. self.assertEqual('thirdparty_package.apps.myapp.models', Cow.__module__)
  147. self.assertEqual('apps.myapp.models', Goat.__module__)
  148. class TestMovedClasses(TestCase):
  149. def setUp(self):
  150. user = UserFactory()
  151. product = create_product()
  152. self.wishlist = WishListFactory(owner=user)
  153. self.wishlist.add(product)
  154. def test_load_formset_old_destination(self):
  155. BaseBasketLineFormSet = get_class('basket.forms', 'BaseBasketLineFormSet')
  156. self.assertEqual('oscar.apps.basket.formsets', BaseBasketLineFormSet.__module__)
  157. StockRecordFormSet = get_class('dashboard.catalogue.forms', 'StockRecordFormSet')
  158. self.assertEqual('oscar.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__)
  159. OrderedProductFormSet = get_class('dashboard.promotions.forms', 'OrderedProductFormSet')
  160. OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm')
  161. # Since OrderedProductFormSet created with metaclass, it has __module__
  162. # attribute pointing to the Django module. Thus, we test if formset was
  163. # loaded correctly by initiating class instance and checking its forms.
  164. self.assertTrue(isinstance(OrderedProductFormSet().forms[0], OrderedProductForm))
  165. LineFormset = get_class('wishlists.forms', 'LineFormset')
  166. WishListLineForm = get_class('wishlists.forms', 'WishListLineForm')
  167. self.assertTrue(isinstance(LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
  168. def test_load_formset_new_destination(self):
  169. BaseBasketLineFormSet = get_class('basket.formsets', 'BaseBasketLineFormSet')
  170. self.assertEqual('oscar.apps.basket.formsets', BaseBasketLineFormSet.__module__)
  171. StockRecordFormSet = get_class('dashboard.catalogue.formsets', 'StockRecordFormSet')
  172. self.assertEqual('oscar.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__)
  173. OrderedProductFormSet = get_class('dashboard.promotions.formsets', 'OrderedProductFormSet')
  174. OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm')
  175. self.assertTrue(isinstance(OrderedProductFormSet().forms[0], OrderedProductForm))
  176. LineFormset = get_class('wishlists.formsets', 'LineFormset')
  177. WishListLineForm = get_class('wishlists.forms', 'WishListLineForm')
  178. self.assertTrue(isinstance(LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
  179. def test_load_formsets_mixed_destination(self):
  180. BaseBasketLineFormSet, BasketLineForm = get_classes(
  181. 'basket.forms', ('BaseBasketLineFormSet', 'BasketLineForm'))
  182. self.assertEqual('oscar.apps.basket.formsets', BaseBasketLineFormSet.__module__)
  183. self.assertEqual('oscar.apps.basket.forms', BasketLineForm.__module__)
  184. StockRecordForm, StockRecordFormSet = get_classes(
  185. 'dashboard.catalogue.forms', ('StockRecordForm', 'StockRecordFormSet')
  186. )
  187. self.assertEqual('oscar.apps.dashboard.catalogue.forms', StockRecordForm.__module__)
  188. OrderedProductForm, OrderedProductFormSet = get_classes(
  189. 'dashboard.promotions.forms', ('OrderedProductForm', 'OrderedProductFormSet')
  190. )
  191. self.assertEqual('oscar.apps.dashboard.promotions.forms', OrderedProductForm.__module__)
  192. self.assertTrue(isinstance(OrderedProductFormSet().forms[0], OrderedProductForm))
  193. LineFormset, WishListLineForm = get_classes('wishlists.forms', ('LineFormset', 'WishListLineForm'))
  194. self.assertEqual('oscar.apps.wishlists.forms', WishListLineForm.__module__)
  195. self.assertTrue(isinstance(LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
  196. class OverriddenClassLoadingTestCase(TestCase):
  197. def test_non_override_class_loader(self):
  198. from oscar.apps.catalogue.views import ProductDetailView
  199. View = get_class('catalogue.views', 'ProductDetailView')
  200. self.assertEqual(View, ProductDetailView)
  201. @override_settings(OSCAR_DYNAMIC_CLASS_LOADER='tests._site.loader.custom_class_loader')
  202. def test_override_class_loader(self):
  203. # Clear lru cache for the class loader
  204. get_class_loader.cache_clear()
  205. View = get_class('catalogue.views', 'ProductDetailView')
  206. self.assertEqual(View, DummyClass)
  207. # Clear lru cache for the class loader again
  208. get_class_loader.cache_clear()