Commits

Olemis Lang committed 3511299

BH Multiproduct #115 : Product environments forward attribute access request to parent environment

Also added :

- sqlparse as dependency
- unittest2 as dependency needed to run the test suite
- compatibility with setuptools 'test' command

Comments (0)

Files changed (1)

t115/t115_r1431447_product_envs_bep3_p1.diff

 # HG changeset patch
-# Parent 6ab12f999a61c3c746b41dd1dfa0455d0f9ed3b9
+# Parent 87807cda82abdfa09cee0fbd9b5d71eb307beee5
 BH Multiproduct #115 : Product environments. Compliance with BEP 3 - part 1
 
-diff -r 6ab12f999a61 bloodhound_multiproduct/multiproduct/env.py
---- a/bloodhound_multiproduct/multiproduct/env.py	Sun Jan 13 01:23:20 2013 -0500
-+++ b/bloodhound_multiproduct/multiproduct/env.py	Sun Jan 13 02:13:29 2013 -0500
+diff -r 87807cda82ab bloodhound_multiproduct/multiproduct/env.py
+--- a/bloodhound_multiproduct/multiproduct/env.py	Sun Jan 13 18:57:57 2013 -0500
++++ b/bloodhound_multiproduct/multiproduct/env.py	Sun Jan 13 22:53:10 2013 -0500
 @@ -52,11 +52,21 @@
  
      implements(ISystemInfoProvider)
          self.product = product
          self.systeminfo = []
          self._href = self._abs_href = None
-@@ -200,9 +198,6 @@
+@@ -200,16 +198,12 @@
  
      # ISystemInfoProvider methods
  
      # Same as parent environment's . Avoid duplicated code
      component_activated = Environment.component_activated.im_func
      _component_name = Environment._component_name.im_func
-@@ -359,58 +354,30 @@
+     _component_rules = Environment._component_rules
+     enable_component = Environment.enable_component.im_func
+     get_known_users = Environment.get_known_users.im_func
+-    get_systeminfo = Environment.get_system_info.im_func
+     get_repository = Environment.get_repository.im_func
+     is_component_enabled = Environment.is_component_enabled.im_func
+ 
+@@ -359,58 +353,30 @@
          """
          # TODO: Handle options args
  
          if format:
              format = format.replace('$(', '%(') \
                       .replace('%(path)s', self.path) \
-@@ -423,25 +390,8 @@
+@@ -423,25 +389,8 @@
          self.log.info('-' * 32 + ' environment startup [Trac %s] ' + '-' * 32,
                        get_pkginfo(core).get('version', VERSION))
  
          return False
  
      def upgrade(self, backup=False, backup_dest=None):
+diff -r 87807cda82ab bloodhound_multiproduct/tests/env.py
+--- a/bloodhound_multiproduct/tests/env.py	Sun Jan 13 18:57:57 2013 -0500
++++ b/bloodhound_multiproduct/tests/env.py	Sun Jan 13 22:53:10 2013 -0500
+@@ -20,9 +20,17 @@
+ 
+ import os.path
+ import shutil
++import sys
+ import tempfile
+-import unittest
++from types import MethodType
+ 
++if sys.version_info < (2, 7):
++    import unittest2 as unittest
++else:
++    import unittest
++
++from trac.config import Option
++from trac.env import Environment
+ from trac.test import EnvironmentStub
+ from trac.tests.env import EnvironmentTestCase
+ 
+@@ -100,6 +108,14 @@
+             # table remains but database version is deleted
+             pass
+ 
++    def _mp_setup(self):
++        """Shortcut for quick product-aware environment setup.
++        """
++        self.env = self._setup_test_env()
++        self._upgrade_mp(self.env)
++        self._setup_test_log(self.env)
++        self._load_product_from_data(self.env, self.default_product)
++
+ class ProductEnvTestCase(EnvironmentTestCase, MultiproductTestCase):
+     r"""Test cases for Trac environments rewritten for product environments
+     """
+@@ -131,9 +147,75 @@
+ 
+         EnvironmentTestCase.tearDown(self)
+ 
+-def suite():
+-    return unittest.makeSuite(ProductEnvTestCase,'test')
++class ProductEnvApiTestCase(MultiproductTestCase):
++    """Assertions for Apache(TM) Bloodhound product-specific extensions in
++    [https://issues.apache.org/bloodhound/wiki/Proposals/BEP-0003 BEP 3]
++    """
++    def setUp(self):
++        self._mp_setup()
++        self.product_env = ProductEnvironment(self.env, self.default_product)
++
++    def test_attr_forward_parent(self):
++        class EnvironmentAttrSandbox(EnvironmentStub):
++            """Limit the impact of class edits so as to avoid race conditions
++            """
++
++        self.longMessage = True
++
++        class AttrSuccess(Exception):
++            """Exception raised when target method / property is actually
++            invoked.
++            """
++
++        def property_mock(attrnm, expected_self):
++            def assertAttrFwd(instance):
++                self.assertIs(instance, expected_self, 
++                        "Mismatch in property '%s'" % (attrnm,))
++                raise AttrSuccess
++            return property(assertAttrFwd)
++
++        self.env.__class__ = EnvironmentAttrSandbox
++        try:
++            for attrnm in 'system_info_providers secure_cookies ' \
++                    'project_admin_trac_url get_system_info get_version ' \
++                    'get_templates_dir get_templates_dir get_log_dir ' \
++                    'backup'.split(): 
++                original = getattr(Environment, attrnm)
++                if isinstance(original, MethodType):
++                    original = getattr(self.env, attrnm)
++                    translation = getattr(self.product_env, attrnm)
++                    self.assertIs(translation.im_self, self.env,
++                            "'%s' not bound to global env in product env" % 
++                                    (attrnm,))
++                    self.assertIs(translation.im_class, EnvironmentAttrSandbox,
++                            "'%s' not bound to 'Environment' in product env" % 
++                                    (attrnm,))
++                    self.assertIs(translation.im_func, original.im_func,
++                            "'%s' function differs in product env" % (attrnm,))
++                elif isinstance(original, (property, Option)):
++                    # Intercept property access e.g. properties, Option, ...
++                    setattr(self.env.__class__, attrnm, 
++                        property_mock(attrnm, self.env))
++
++                    with self.assertRaises(AttrSuccess) as cm_test_attr:
++                        getattr(self.product_env, attrnm)
++                else:
++                    self.fail("Environment member %s has unexpected type" % 
++                            (repr(original),))
++        finally:
++            self.env.__class__ = EnvironmentStub
++
++    def tearDown(self):
++        # Release reference to transient environment mock object
++        self.env = None
++        self.product_env = None
++
++def test_suite():
++    return unittest.TestSuite([
++            unittest.makeSuite(ProductEnvTestCase,'test'),
++            unittest.makeSuite(ProductEnvApiTestCase, 'test')
++        ])
+ 
+ if __name__ == '__main__':
+-    unittest.main(defaultTest='suite')
++    unittest.main(defaultTest='test_suite')
+ 
+diff -r 87807cda82ab bloodhound_theme/setup.py
+--- a/bloodhound_theme/setup.py	Sun Jan 13 18:57:57 2013 -0500
++++ b/bloodhound_theme/setup.py	Sun Jan 13 22:53:10 2013 -0500
+@@ -19,6 +19,7 @@
+ #  under the License.
+ 
+ from setuptools import setup
++import sys
+ 
+ setup(
+   name = 'BloodhoundTheme',
+@@ -34,6 +35,7 @@
+       'Framework :: Trac',
+     ],
+   install_requires = ['BloodhoundDashboardPlugin', 'TracThemeEngine', 'Trac'],
++  tests_require = ['unittest2'] if sys.version_info < (2, 7) else [],
+   entry_points = {
+       'trac.plugins': [
+             'bhtheme.theme = bhtheme.theme',