incubator-bloodhound-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1433320 - in /incubator/bloodhound/branches/bep_0003_multiproduct: bloodhound_multiproduct/multiproduct/env.py bloodhound_multiproduct/tests/env.py bloodhound_theme/setup.py
Date Tue, 15 Jan 2013 09:30:22 GMT
Author: jure
Date: Tue Jan 15 09:30:22 2013
New Revision: 1433320

URL: http://svn.apache.org/viewvc?rev=1433320&view=rev
Log:
Towards #115, patch t115_r1431447_product_envs_bep3_p1.diff from olemis


Modified:
    incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
    incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/env.py
    incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/setup.py

Modified: incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py?rev=1433320&r1=1433319&r2=1433320&view=diff
==============================================================================
--- incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
(original)
+++ incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
Tue Jan 15 09:30:22 2013
@@ -46,7 +46,7 @@ class Environment(trac.env.Environment):
     def __init__(self, path, create=False, options=[]):
         super(Environment, self).__init__(path, create=create, options=options)
         # global environment w/o parent
-        self.env = None
+        self.parent = None
         self.product = None
 
     @property
@@ -82,11 +82,23 @@ class ProductEnvironment(Component, Comp
 
     implements(trac.env.ISystemInfoProvider)
 
-    @property
-    def system_info_providers(self):
-        r"""System info will still be determined by the global environment.
-        """
-        return self.env.system_info_providers
+    def __getattr__(self, attrnm):
+        """Forward attribute access request to parent environment.
+
+        Initially this will affect the following members of
+        `trac.env.Environment` class:
+
+        system_info_providers, secure_cookies, project_admin_trac_url,
+        get_system_info, get_version, get_templates_dir, get_templates_dir,
+        get_log_dir, backup
+        """
+        try:
+            if attrnm == 'parent':
+                raise AttributeError
+            return getattr(self.parent, attrnm)
+        except AttributeError:
+            raise AttributeError("'%s' object has no attribute '%s'" %
+                    (self.__class__.__name__, attrnm))
 
     @property
     def setup_participants(self):
@@ -116,12 +128,6 @@ class ProductEnvironment(Component, Comp
     base_url_for_redirect = ''
 
     @property
-    def secure_cookies(self):
-        """Restrict cookies to HTTPS connections.
-        """
-        return self.env.secure_cookies
-
-    @property
     def project_name(self):
         """Name of the product.
         """
@@ -139,24 +145,18 @@ class ProductEnvironment(Component, Comp
         which the `base_url` resides. This is used in notification
         e-mails.
         """
-        return self.env.project_url
+        # FIXME: Should products have different values i.e. config option ?
+        return self.parent.project_url
 
     project_admin = Option('project', 'admin', '',
         """E-Mail address of the product's leader / administrator.""")
 
     @property
-    def project_admin_trac_url(self):
-        """Base URL of a Trac instance where errors in this Trac
-        should be reported.
-        """
-        return self.env.project_admin_trac_url
-
-    # FIXME: Should products have different values i.e. config option ?
-    @property
     def project_footer(self):
         """Page footer text (right-aligned).
         """
-        return self.env.project_footer
+        # FIXME: Should products have different values i.e. config option ?
+        return self.parent.project_footer
 
     project_icon = Option('project', 'icon', 'common/trac.ico',
         """URL of the icon of the product.""")
@@ -207,6 +207,12 @@ class ProductEnvironment(Component, Comp
         :param product: product prefix or an instance of
                         multiproduct.model.Product
         """
+        if not isinstance(env, trac.env.Environment):
+            raise TypeError("Initializer must be called with " \
+                "trac.env.Environment instance as first argument " \
+                "(got %s instance instead)" % 
+                        (self._component_name(env.__class__),) )
+
         ComponentManager.__init__(self)
 
         if isinstance(product, Product):
@@ -221,9 +227,9 @@ class ProductEnvironment(Component, Comp
                         product, products)
                 raise LookupError("Missing product %s" % (product,))
 
-        self.env = env
+        self.parent = env
         self.product = product
-        self.path = self.env.path
+        self.path = self.parent.path
         self.systeminfo = []
         self._href = self._abs_href = None
 
@@ -231,16 +237,12 @@ class ProductEnvironment(Component, Comp
 
     # ISystemInfoProvider methods
 
-    def get_system_info(self):
-        return self.env.get_system_info()
-
     # Same as parent environment's . Avoid duplicated code
     component_activated = trac.env.Environment.component_activated.im_func
     _component_name = trac.env.Environment._component_name.im_func
     _component_rules = trac.env.Environment._component_rules
     enable_component = trac.env.Environment.enable_component.im_func
     get_known_users = trac.env.Environment.get_known_users.im_func
-    get_systeminfo = trac.env.Environment.get_system_info.im_func
     get_repository = trac.env.Environment.get_repository.im_func
     is_component_enabled = trac.env.Environment.is_component_enabled.im_func
 
@@ -264,7 +266,7 @@ class ProductEnvironment(Component, Comp
                ...
         """
         # share connection pool with global environment
-        return self.env.get_db_cnx()
+        return self.parent.get_db_cnx()
 
     @lazy
     def db_exc(self):
@@ -282,7 +284,7 @@ class ProductEnvironment(Component, Comp
                 ...
         """
         # exception types same as in global environment
-        return self.env.db_exc()
+        return self.parent.db_exc()
 
     def with_transaction(self, db=None):
         """Decorator for transaction functions :deprecated:"""
@@ -293,7 +295,7 @@ class ProductEnvironment(Component, Comp
 
         See `trac.db.api.get_read_db` for detailed documentation."""
         # database connection is shared with global environment
-        return self.env.get_read_db()
+        return self.parent.get_read_db()
 
     @property
     def db_query(self):
@@ -328,7 +330,7 @@ class ProductEnvironment(Component, Comp
           `db_transaction`).
         """
         BloodhoundIterableCursor.set_env(self)
-        return QueryContextManager(self.env)
+        return QueryContextManager(self.parent)
 
     @property
     def db_transaction(self):
@@ -364,7 +366,7 @@ class ProductEnvironment(Component, Comp
           (`db_query` or `db_transaction`).
         """
         BloodhoundIterableCursor.set_env(self)
-        return TransactionContextManager(self.env)
+        return TransactionContextManager(self.parent)
 
     def shutdown(self, tid=None):
         """Close the environment."""
@@ -385,58 +387,30 @@ class ProductEnvironment(Component, Comp
         """
         # TODO: Handle options args
 
-    def get_version(self, db=None, initial=False):
-        """Return the current version of the database.  If the
-        optional argument `initial` is set to `True`, the version of
-        the database used at the time of creation will be returned.
-
-        In practice, for database created before 0.11, this will
-        return `False` which is "older" than any db version number.
-
-        :since: 0.11
-
-        :since 1.0: deprecation warning: the `db` parameter is no
-                    longer used and will be removed in version 1.1.1
-        """
-        return self.env.get_version(db, initial)
-
     def setup_config(self):
         """Load the configuration object.
         """
         # FIXME: Install product-specific configuration object
-        self.config = self.env.config
+        self.config = self.parent.config
         self.setup_log()
 
-    def get_templates_dir(self):
-        """Return absolute path to the templates directory.
-        """
-        return self.env.get_templates_dir()
-
-    def get_htdocs_dir(self):
-        """Return absolute path to the htdocs directory."""
-        return self.env.get_htdocs_dir()
-
-    def get_log_dir(self):
-        """Return absolute path to the log directory."""
-        return self.env.get_log_dir()
-
     def setup_log(self):
         """Initialize the logging sub-system."""
         from trac.log import logger_handler_factory
         logtype = self.log_type
-        self.env.log.debug("Log type '%s' for product '%s'", 
+        self.parent.log.debug("Log type '%s' for product '%s'", 
                 logtype, self.product.prefix)
         if logtype == 'inherit':
-            logtype = self.env.log_type
-            logfile = self.env.log_file
-            format = self.env.log_format
+            logtype = self.parent.log_type
+            logfile = self.parent.log_file
+            format = self.parent.log_format
         else:
             logfile = self.log_file
             format = self.log_format
         if logtype == 'file' and not os.path.isabs(logfile):
             logfile = os.path.join(self.get_log_dir(), logfile)
         logid = 'Trac.%s.%s' % \
-                (sha1(self.env.path).hexdigest(), self.product.prefix)
+                (sha1(self.parent.path).hexdigest(), self.product.prefix)
         if format:
             format = format.replace('$(', '%(') \
                      .replace('%(path)s', self.path) \
@@ -449,25 +423,8 @@ class ProductEnvironment(Component, Comp
         self.log.info('-' * 32 + ' environment startup [Trac %s] ' + '-' * 32,
                       get_pkginfo(core).get('version', VERSION))
 
-    def backup(self, dest=None):
-        """Create a backup of the database.
-
-        :param dest: Destination file; if not specified, the backup is
-                     stored in a file called db_name.trac_version.bak
-        """
-        return self.env.backup(dest)
-
     def needs_upgrade(self):
         """Return whether the environment needs to be upgraded."""
-        #for participant in self.setup_participants:
-        #    with self.db_query as db:
-        #        if participant.environment_needs_upgrade(db):
-        #            self.log.warn("Component %s requires environment upgrade",
-        #                          participant)
-        #            return True
-
-        # FIXME: For the time being no need to upgrade the environment
-        # TODO: Determine the role of product environments at upgrade time
         return False
 
     def upgrade(self, backup=False, backup_dest=None):

Modified: incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/env.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/env.py?rev=1433320&r1=1433319&r2=1433320&view=diff
==============================================================================
--- incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/env.py
(original)
+++ incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/env.py
Tue Jan 15 09:30:22 2013
@@ -20,9 +20,20 @@
 
 import os.path
 import shutil
+import sys
 import tempfile
-import unittest
 
+from sqlite3 import OperationalError
+
+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 +111,14 @@ class MultiproductTestCase(unittest.Test
             # 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 +150,98 @@ class ProductEnvTestCase(EnvironmentTest
 
         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):
+                    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_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
+
+        for attrnm in 'component_activated _component_rules ' \
+                'enable_component get_known_users get_repository ' \
+                'is_component_enabled _component_name'.split():
+            original = getattr(Environment, attrnm)
+            if isinstance(original, MethodType):
+                translation = getattr(self.product_env, attrnm)
+                self.assertIs(translation.im_self, self.product_env,
+                        "'%s' not bound to product env" % (attrnm,))
+                self.assertIs(translation.im_func, original.im_func,
+                        "'%s' function differs in product env" % (attrnm,))
+            elif isinstance(original, property):
+                translation = getattr(ProductEnvironment, attrnm)
+                self.assertIs(original, translation,
+                        "'%s' property differs in product env" % (attrnm,))
+
+    def test_typecheck(self):
+        self._load_product_from_data(self.env, 'tp2')
+        with self.assertRaises(TypeError) as cm_test:
+            new_env = ProductEnvironment(self.product_env, 'tp2')
+
+        #msg = str(cm_test.exception)
+        #expected_msg = "Initializer must be called with " \
+        #        "trac.env.Environment instance as first argument " \
+        #        "(got multiproduct.env.ProductEnvironment instance instead)"
+        #self.assertEqual(msg, expected_msg)
+
+    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')
 

Modified: incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/setup.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/setup.py?rev=1433320&r1=1433319&r2=1433320&view=diff
==============================================================================
--- incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/setup.py (original)
+++ incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/setup.py Tue Jan
15 09:30:22 2013
@@ -19,6 +19,7 @@
 #  under the License.
 
 from setuptools import setup
+import sys
 
 setup(
   name = 'BloodhoundTheme',
@@ -34,6 +35,7 @@ setup(
       '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',



Mime
View raw message