1. Olemis Lang
  2. bloodhound-mq

Commits

Olemis Lang  committed d61428b

BH Multiproduct #387 : FunctionalProductEnvironment . Enter product test env context in test case's in_product()

  • Participants
  • Parent commits 3e26a53
  • Branches t387_test_functional

Comments (0)

Files changed (1)

File t387/t387_r1515319_functional_test.6.diff

View file
  • Ignore whitespace
 
 diff -r dc26c55b4721 bloodhound_multiproduct/tests/functional/__init__.py
 --- a/bloodhound_multiproduct/tests/functional/__init__.py	Thu Aug 29 12:43:46 2013 -0500
-+++ b/bloodhound_multiproduct/tests/functional/__init__.py	Sat Aug 31 17:30:29 2013 -0500
-@@ -35,9 +35,10 @@
++++ b/bloodhound_multiproduct/tests/functional/__init__.py	Sun Sep 01 03:38:27 2013 -0500
+@@ -17,6 +17,7 @@
+ #  specific language governing permissions and limitations
+ #  under the License.
+ 
++import contextlib
+ import imp
+ from inspect import isclass
+ import os
+@@ -35,9 +36,11 @@
  from trac.util.compat import close_fds
  from trac.util.text import unicode_quote
  from trac.web.href import Href
 +
  from multiproduct.api import MultiProductSystem
++from multiproduct.env import ProductEnvironment
  from multiproduct import hooks
 -
 +from multiproduct.product_admin import ProductAdminModule
  from tests import unittest
  
  #----------------
-@@ -57,6 +58,7 @@
+@@ -57,6 +60,7 @@
      def init(self):
          """Determine the location of Trac source code
          """
          self.bhmp_upgrade = False
          self.trac_src = os.path.realpath(os.path.join( 
                  __import__('trac', []).__file__, '..' , '..'))
-@@ -252,6 +254,17 @@
+@@ -114,7 +118,7 @@
+         """Default implementation just returning href object for global
+         environment and failing if product prefix is specified.
+         """
+-        if envname not in ('trac', None):
++        if envname not in (self.bh_install_project, None):
+             raise LookupError('Unknown environment ' + repr(envname))
+         if prefix is not None:
+             self._fail_no_mp_setup()
+@@ -205,16 +209,11 @@
+         plugins_dir = global_env.shared_plugins_dir
+         load_components(global_env, plugins_dir and (plugins_dir,))
+ 
+-    def product_test_env(self, product_id):
+-        """Functional test environment for product
++    def product_testenv(self, product_id):
++        return FunctionalProductEnvironment(self, product_id)
+ 
+-        @param product_id: target product prefix
+-        @return: an object reusing resources in target functional test
+-                 environment to implement a compatible interface for
+-                 a given product environment
+-        @raise LookupError: if there's no product for given prefix
+-        """
+-        raise NotImplementedError()
++    def product_environment(self, product_id):
++        return ProductEnvironment(self.get_trac_environment(), product_id)
+ 
+     def configure_web_hooks(self):
+         """Setup web bootstrap_handlers and generation of product and global
+@@ -238,6 +237,8 @@
+         global environment.
+         """
+         def _default_base_href(user=None, prefix=None, envname=None):
++            if envname not in (self.bh_install_project, None):
++                raise LookupError('Unknown environment ' + repr(envname))
+             # TODO: Does not generate /login ? Should it ?
+             parts = urllib2.urlparse.urlsplit(self.url)
+             if not user or user == 'anonymous':
+@@ -252,6 +253,17 @@
  
      # Protected methods
  
      def _bloodhound_install(self):
          """Execute Bloodhound installer script
          """
-@@ -267,29 +280,22 @@
+@@ -267,29 +279,22 @@
                                        os.path.join(self.bh_src, 'installer',
                                                     'bloodhound_setup.py'))
  
          finally:
              os.chdir(cwd)
  
-@@ -652,9 +658,10 @@
+@@ -307,6 +312,53 @@
+         return MultiProductSystem(env).default_product_prefix
+ 
+ 
++# TODO: Virtual ABCs for isinstance() checks
++# TODO: Assess implications of forwarding methods to global test env
++class FunctionalProductEnvironment(object):
++    """Functional test environment limiting interactions to product context
++    """
++    def __init__(self, testenv, product_id):
++        """Initialize functional product environment
++
++        @param product_id: target product prefix
++        @return: an object reusing resources in target functional test
++                 environment to implement a compatible interface for
++                 a given product environment
++        @raise LookupError: if there's no product for given prefix
++        """
++        self.parent = testenv
++        self.prefix = product_id
++        self.url = self.parent.get_env_href(prefix=product_id)
++        ProductEnvironment(testenv.get_trac_environment(), self.prefix)
++
++    def _tracadmin(self, *args, **kwargs): 
++        """Execute trac-admin command in target product context by default
++        """
++        product_id = kwargs.get('product')
++        if product_id is None:
++            kwargs['product'] = self.prefix
++        return self.parent._tracadmin(*args, **kwargs)
++
++    def get_trac_environment(self):
++        return ProductEnvironment(self.parent.get_trac_environment(),
++                                  self.prefix)
++
++    def create(self):
++        raise RuntimeError('Bloodhound test environment already created')
++
++    def _bloodhound_install(self):
++        raise RuntimeError('Bloodhound test environment already created')
++
++    def __getattr__(self, attrnm):
++        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))
++
++
+ class BloodhoundFunctionalTester(FunctionalTester):
+     """Leverages Trac library of higher-level operations for interacting with
+     a fully featured Apache(TM) Bloodhound test environment.
+@@ -652,9 +704,10 @@
      As a consequence some methods of Trac functional tester have to be
      executed in special ways.
      """
  
      class in_product(BloodhoundFunctionalTester.in_product):
          """Context manager temporarily switching to product URL
-@@ -744,10 +751,26 @@
+@@ -744,10 +797,26 @@
  
      tester_class = BloodhoundGlobalEnvFunctionalTester
  
          except:
              # Ensure tracd process is killed on failure
              print "Stopping web server...\n"
+@@ -770,6 +839,7 @@
+         order access default product URL namespace instead of global.
+         """
+         self.setUp()
++        # FIXME: Loop once over test cases
+         if hasattr(self, 'fixture'):
+             for test in self._tests:
+                 if hasattr(test, 'setFixture'):
+@@ -778,10 +848,20 @@
+         for test in self._tests:
+             if result.shouldStop:
+                 break
+-            if getattr(test, 'BH_IN_DEFAULT_PRODUCT', False) and \
+-                    hasattr(self._tester, 'in_product'):
+-                with self._tester.in_product(self._tester):
+-                    test(result)
++            if getattr(test, 'BH_IN_DEFAULT_PRODUCT', False):
++                if hasattr(test, 'in_product'):
++                    with test.in_product():
++                        test(result)
++                elif hasattr(self._tester, 'in_product'):
++                    with self._tester.in_product(self._tester):
++                        test(result)
++                else:
++                    try:
++                        raise RuntimeError('Impossible to run test %s in '
++                                           'default product' % (test,))
++                    except:
++                        err = sys.exc_info()
++                    result.addError(test, err)
+             else:
+                 test(result)
+         self.tearDown()
+@@ -801,11 +881,27 @@
+         :param prefix:  target product prefix
+         :return:        context manager object
+         """
++        # Force setting tester and test environment
++        functional.FunctionalTestCaseSetup.setUp(self)
++
++        @contextlib.contextmanager
++        def in_product_testenv(product_id):
++            try:
++                # Backup active test env
++                original = self._testenv
++                self._testenv = original.product_testenv(product_id)
++                yield self._testenv
++            finally:
++                self._testenv = original
++
+         if prefix is None:
+-            return self._tester.in_product(self._tester)
++            default_product = self._testenv._default_product()
++            return contextlib.nested(in_product_testenv(default_product),
++                                     self._tester.in_product(self._tester))
+         else:
+             product_href = self._testenv.get_env_href(prefix=prefix)
+-            return self._tester.in_product(self._tester, product_href())
++            return contextlib.nested(in_product_testenv(prefix),
++                          self._tester.in_product(self._tester, product_href()))
+ 
+ # Mark some test cases to be run against default product
+ import trac.ticket.tests.functional