Ejemplo n.º 1
0
def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
  if "zeo_client" in os.environ and "zeo_server" in os.environ:
    _print("conflicting options: --zeo_client and --zeo_server")
    sys.exit(1)
  instance_home =  os.environ['INSTANCE_HOME']
  os.environ.setdefault('EVENT_LOG_FILE', os.path.join(tests_home, 'zLOG.log'))
  os.environ.setdefault('EVENT_LOG_SEVERITY', '-300')

  _print("Loading Zope ... \n")
  _start = time.time()

  import Testing
  # the above import changes cfg.testinghome. Reset it to where our
  # custom_zodb.py can be found. This must be done before importing
  # ZopeTestCase below (Leo: I hate import side-effects with a passion).
  import App.config
  cfg = App.config.getConfiguration()
  cfg.testinghome = instance_home
  cfg.instancehome = instance_home
  from Zope2.Startup.datatypes import DBTab
  cfg.dbtab = DBTab({}, {})
  App.config.setConfiguration(cfg)

  if WIN:
    products_home = os.path.join(real_instance_home, 'Products')
    import Products
    Products.__path__.insert(0, products_home)
  else:
    products_home = os.path.join(instance_home, 'Products')

  from Testing.ZopeTestCase import layer, PortalTestCase, ZopeLite
  _apply_patches = layer._deferred_setup.pop(0)[0]
  assert _apply_patches.__name__ == '_apply_patches'

  # Set debug mode after importing ZopeLite that resets it to 0
  cfg.debug_mode = debug

  from ZConfig.components.logger import handlers, logger, loghandler
  import logging
  root_logger = logging.getLogger()
  # On recent Zope, ZopeTestCase does not have any logging facility.
  # So we must emulate the usual Zope startup code to catch log messages.
  from ZConfig.matcher import SectionValue
  section = SectionValue({'dateformat': '%Y-%m-%d %H:%M:%S',
                          'format': '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s',
                          'level': logging.INFO,
                          'path': os.environ['EVENT_LOG_FILE'],
                          'max_size': None,
                          'old_files': None,
                          'when': None,
                          'interval': None,
                          'formatter': None,
                          },
                         None, None)
  section.handlers = [handlers.FileHandlerFactory(section)]
  root_logger.handlers = []
  logger.EventLogFactory(section)()

  # Make sure that locally overridden python modules are used
  sys.path.insert(0, os.path.join(real_instance_home, 'lib', 'python'))

  # allow unit tests of our Products or business templates to be reached.
  sys.path += glob(os.path.join(products_home, '*', 'tests'))
  bt5_path_list = os.environ['erp5_tests_bt5_path'].split(',')
  bt5_path_list += [os.path.join(path, "*") for path in bt5_path_list]
  for path in bt5_path_list:
    path = os.path.join(path,'*','TestTemplateItem')
    sys.path += glob(path)
    sys.path += glob(os.path.join(path, 'portal_components'))

  sys.path += (os.path.join(real_instance_home, 'tests'),
               tests_home, instance_home)

  # change current directory to the test home, to create zLOG.log in this dir.
  os.chdir(tests_home)

  from Products.ERP5Type.patches import noZopeHelp
  from OFS.Application import AppInitializer
  AppInitializer.install_session_data_manager = lambda self: None

  # import ERP5TypeTestCase before calling layer.ZopeLite.setUp
  # XXX What if the unit test itself uses 'onsetup' ? We should be able to call
  #     remaining 'onsetup' hooks just before executing the test suite.
  from Products.ERP5Type.tests.ERP5TypeTestCase import \
      ProcessingNodeTestCase, ZEOServerTestCase, dummy_setUp, dummy_tearDown

  # Since we're not using the zope.testing testrunner, we need to set up
  # the layer ourselves
  # FIXME: We should start using Zope layers. Our setup will probably
  # be faster and we could drop most of this code we currently maintain
  # ourselves
  layer.ZopeLite.setUp() # this will import custom_zodb.py
  def assertFalse():
    assert False
  layer.onsetup = assertFalse
  ZopeLite._theApp._p_jar.close()
  ZopeLite._theApp = None

  from Products.ERP5Type.tests.utils import DbFactory
  root_db_name, = cfg.dbtab.databases.keys()
  DbFactory(root_db_name).addMountPoint('/')

  TestRunner = unittest.TextTestRunner

  import Lifetime
  from Zope2.custom_zodb import Storage, save_mysql, \
      node_pid_list, neo_cluster, zeo_server_pid
  def shutdown(signum, frame, signum_set=set()):
    Lifetime.shutdown(0)
    signum_set.add(signum)
    if node_pid_list is None and len(signum_set) > 1:
      # in case of ^C, a child should also receive a SIGHUP from the parent,
      # so we merge the first 2 different signals in a single exception
      signum_set.remove(signal.SIGHUP)
    else:
      raise KeyboardInterrupt
  if signal.getsignal(signal.SIGINT) is not signal.SIG_IGN:
    signal.signal(signal.SIGINT, shutdown)
  signal.signal(signal.SIGHUP, shutdown)

  coverage_config = os.environ.get('coverage', None)
  if coverage_config:
    coverage_process = coverage(config_file=coverage_config)
    coverage_process.start()

  try:
    save = int(os.environ.get('erp5_save_data_fs', 0))
    load = int(os.environ.get('erp5_load_data_fs', 0))
    dummy = save and (int(os.environ.get('update_business_templates', 0))
                      or not load)
    if zeo_server_pid == 0:
      suite = ZEOServerTestCase('asyncore_loop')
    elif node_pid_list is None or not test_list:
      suite = ProcessingNodeTestCase('processing_node')
      if not (dummy or load):
        _print('WARNING: either --save or --load should be used because static'
               ' files are only reloaded by the node installing business'
               ' templates.')
    else:
      if dummy:
        # Skip all tests and monkeypatch PortalTestCase to skip
        # afterSetUp/beforeTearDown.
        ERP5TypeTestLoader._testMethodPrefix = 'dummy_test'
        PortalTestCase.setUp = dummy_setUp
        PortalTestCase.tearDown = dummy_tearDown
      elif debug:
        # Hack the profiler to run only specified test methods,
        # and wrap results when running in debug mode.
        class DebugTextTestRunner(TestRunner):
          def _makeResult(self):
            result = super(DebugTextTestRunner, self)._makeResult()
            return DebugTestResult(result)
        TestRunner = DebugTextTestRunner
      loader = ERP5TypeTestLoader()
      if run_only:
        ERP5TypeTestLoader.filter_test_list = [re.compile(x).search for x in
            run_only.split(',')]

      suite = loader.loadTestsFromNames(test_list)
      if run_only:
        ERP5TypeTestLoader.filter_test_list = None

    if node_pid_list is None:
      result = suite()
    else:
      if not test_list:
        root_logger.handlers.append(loghandler.StreamHandler(sys.stderr))
      _print('done (%.3fs)\n' % (time.time() - _start))
      result = TestRunner(verbosity=verbosity).run(suite)
    transaction.commit()
  except:
    import traceback
    print "runUnitTestList Exception : %r" % (traceback.print_exc(),)
    # finally does not expect opened transaction, even in the
    # case of a Ctrl-C.
    transaction.abort()
    raise
  finally:
    ProcessingNodeTestCase.unregisterNode()
    Storage.close()
    if node_pid_list is not None:
      # Wait that child processes exit. Stop ZEO storage (if any) after all
      # other nodes disconnected.
      for pid in node_pid_list:
        os.kill(pid, signal.SIGHUP)
      for pid in node_pid_list:
        os.waitpid(pid, 0)
      if zeo_server_pid:
        os.kill(zeo_server_pid, signal.SIGHUP)
        os.waitpid(zeo_server_pid, 0)
      if neo_cluster:
        neo_cluster.stop()

  if coverage_config:
    coverage_process.stop()
    coverage_process.save()
    coverage_process.html_report()

  if save and save_mysql:
    save_mysql(verbosity)

  return result
Ejemplo n.º 2
0
def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
  if "zeo_client" in os.environ and "zeo_server" in os.environ:
    _print("conflicting options: --zeo_client and --zeo_server")
    sys.exit(1)
  instance_home =  os.environ['INSTANCE_HOME']
  os.environ.setdefault('EVENT_LOG_FILE', os.path.join(tests_home, 'zLOG.log'))
  os.environ.setdefault('EVENT_LOG_SEVERITY', '-300')

  _print("Loading Zope ... \n")
  _start = time.time()

  import Testing
  # the above import changes cfg.testinghome. Reset it to where our
  # custom_zodb.py can be found. This must be done before importing
  # ZopeTestCase below (Leo: I hate import side-effects with a passion).
  import App.config
  cfg = App.config.getConfiguration()
  cfg.testinghome = instance_home
  cfg.instancehome = instance_home
  try:
    from Zope2.Startup.datatypes import DBTab
    cfg.dbtab = DBTab({}, {})
  except ImportError: # Zope 2.8
    pass
  App.config.setConfiguration(cfg)

  if WIN:
    products_home = os.path.join(real_instance_home, 'Products')
    import Products
    Products.__path__.insert(0, products_home)
  else:
    products_home = os.path.join(instance_home, 'Products')

  # The following un-monkey-patch is only required for Zope 2.8.
  # On Zope 2.12, import_products() is called by ERP5TestCase before it is
  # patched by the layer.setUp() call.
  import OFS.Application
  import_products = OFS.Application.import_products
  from Testing import ZopeTestCase # Zope 2.8: this will import custom_zodb.py
  OFS.Application.import_products = import_products

  from ZConfig.components.logger import handlers, logger, loghandler
  import logging
  root_logger = logging.getLogger()
  try:
    # On Zope 2.8, ZopeTestCase does not have any logging facility.
    # So we must emulate the usual Zope startup code to catch log
    # messages.
    from ZConfig.matcher import SectionValue
    section = SectionValue({'dateformat': '%Y-%m-%d %H:%M:%S',
                            'format': '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s',
                            'level': logging.INFO,
                            'path': os.environ['EVENT_LOG_FILE'],
                            'max_size': None,
                            'old_files': None,
                            'when': None,
                            'interval': None,
                            'formatter': None,
                            },
                           None, None)
    section.handlers = [handlers.FileHandlerFactory(section)]
    root_logger.handlers = []
    logger.EventLogFactory(section)()
  except ImportError:
    pass

  # allow unit tests of our Products or business templates to be reached.
  product_test_list = glob(os.path.join(products_home, '*', 'tests'))
  sys.path.extend(product_test_list)
  erp5_tests_bt5_path = os.environ.get('erp5_tests_bt5_path',
                              os.path.join(instance_home, 'bt5'))
  bt5_path_list = erp5_tests_bt5_path.split(",")
  bt5_test_list = []
  project_bt5_test_list = []
  for bt5_path in bt5_path_list:
    bt5_test_list.extend(glob(os.path.join(bt5_path,'*','TestTemplateItem')))
    # also suport instance_home/bt5/project_bt5/*
    project_bt5_test_list.extend(glob(os.path.join(bt5_path, '*', '*',
                                                         'TestTemplateItem')))
  sys.path.extend(bt5_test_list)
  sys.path.extend(project_bt5_test_list)

  sys.path.extend((os.path.join(real_instance_home, 'tests'), tests_home))
  sys.path.append(instance_home)
  # Make sure that locally overridden python modules are used
  sys.path.insert(0, os.path.join(real_instance_home, 'lib', 'python'))

  # XXX Allowing to load modules from here is a wrong idea. use the above path
  # instead.
  # Add tests_framework_home as first path element.
  # this allows to bypass psyco by creating a dummy psyco module
  # it is then possible to run the debugger by "import pdb; pdb.set_trace()"
  sys.path.insert(0, tests_framework_home)

  # change current directory to the test home, to create zLOG.log in this dir.
  os.chdir(tests_home)

  # import ERP5TypeTestCase before calling layer.ZopeLite.setUp
  # XXX What if the unit test itself uses 'onsetup' ? We should be able to call
  #     remaining 'onsetup' hooks just before executing the test suite.
  from Products.ERP5Type.tests.ERP5TypeTestCase import \
      ProcessingNodeTestCase, ZEOServerTestCase, dummy_setUp, dummy_tearDown
  try:
    from Testing.ZopeTestCase import layer
  except ImportError:
    #  Zope 2.8, no need to set-up the ZopeLite layer
    pass
  else:
    # Since we're not using the zope.testing testrunner, we need to set up
    # the layer ourselves
    # FIXME: We should start using Zope layers. Our setup will probably
    # be faster and we could drop most of this code we currently maintain
    # ourselves
    layer.ZopeLite.setUp() # Zope 2.12: this will import custom_zodb.py
    def assertFalse():
      assert False
    layer.onsetup = assertFalse

    from Products.ERP5Type.tests.utils import DbFactory
    root_db_name, = cfg.dbtab.databases.keys()
    DbFactory(root_db_name).addMountPoint('/')

  TestRunner = backportUnittest.TextTestRunner

  import Lifetime
  from Zope2.custom_zodb import Storage, save_mysql, \
      node_pid_list, neo_cluster, zeo_server_pid
  def shutdown(signum, frame, signum_set=set()):
    Lifetime.shutdown(0)
    signum_set.add(signum)
    if node_pid_list is None and len(signum_set) > 1:
      # in case of ^C, a child should also receive a SIGHUP from the parent,
      # so we merge the first 2 different signals in a single exception
      signum_set.remove(signal.SIGHUP)
    else:
      raise KeyboardInterrupt
  if signal.getsignal(signal.SIGINT) is not signal.SIG_IGN:
    signal.signal(signal.SIGINT, shutdown)
  signal.signal(signal.SIGHUP, shutdown)

  try:
    save = int(os.environ.get('erp5_save_data_fs', 0))
    load = int(os.environ.get('erp5_load_data_fs', 0))
    dummy = save and (int(os.environ.get('update_business_templates', 0))
                      or not load)
    if zeo_server_pid == 0:
      suite = ZEOServerTestCase('asyncore_loop')
    elif node_pid_list is None or not test_list:
      suite = ProcessingNodeTestCase('processing_node')
      if not (dummy or load):
        _print('WARNING: either --save or --load should be used because static'
               ' files are only reloaded by the node installing business'
               ' templates.')
    else:
      if dummy:
        # Skip all tests and monkeypatch PortalTestCase to skip
        # afterSetUp/beforeTearDown.
        ERP5TypeTestLoader._testMethodPrefix = 'dummy_test'
        ZopeTestCase.PortalTestCase.setUp = dummy_setUp
        ZopeTestCase.PortalTestCase.tearDown = dummy_tearDown
      elif debug:
        # Hack the profiler to run only specified test methods,
        # and wrap results when running in debug mode.
        class DebugTextTestRunner(TestRunner):
          def _makeResult(self):
            result = super(DebugTextTestRunner, self)._makeResult()
            return DebugTestResult(result)
        TestRunner = DebugTextTestRunner
      loader = ERP5TypeTestLoader()
      if run_only:
        ERP5TypeTestLoader.filter_test_list = [re.compile(x).search for x in
            run_only.split(',')]

      suite = loader.loadTestsFromNames(test_list)
      if run_only:
        ERP5TypeTestLoader.filter_test_list = None

    if node_pid_list is None:
      result = suite()
    else:
      if not test_list:
        root_logger.handlers.append(loghandler.StreamHandler(sys.stderr))
      _print('done (%.3fs)\n' % (time.time() - _start))
      result = TestRunner(verbosity=verbosity).run(suite)
  finally:
    ProcessingNodeTestCase.unregisterNode()
    Storage.close()
    if node_pid_list is not None:
      # Wait that child processes exit. Stop ZEO storage (if any) after all
      # other nodes disconnected.
      for pid in node_pid_list:
        os.kill(pid, signal.SIGHUP)
      for pid in node_pid_list:
        os.waitpid(pid, 0)
      if zeo_server_pid:
        os.kill(zeo_server_pid, signal.SIGHUP)
        os.waitpid(zeo_server_pid, 0)
      if neo_cluster:
        neo_cluster.stop()

  if save:
    os.chdir(instance_home)
    if save_mysql:
      save_mysql(verbosity)
    if suite.__class__ not in (ProcessingNodeTestCase, ZEOServerTestCase):
      # Static files are modified by the node installing business templates,
      # i.e. by the node running the unit test. There is no point saving them
      # on a ZEO server, or on nodes that only process activities: this has to
      # be done manually.
      if verbosity:
        _print('Dumping static files...\n')
      live_instance_path = os.environ.get('live_instance_path')
      for static_dir in static_dir_list:
        if os.path.islink(static_dir):
          continue
        if live_instance_path:
          backup_path = os.path.join(live_instance_path, static_dir)
        else:
          backup_path = static_dir + '.bak'
        try:
          shutil.rmtree(backup_path)
        except OSError, e:
          if e.errno != errno.ENOENT:
            raise
        os.rename(static_dir, backup_path)
    elif node_pid_list is not None:
      _print('WARNING: No static files saved. You will have to do it manually.')
Ejemplo n.º 3
0
def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
    if "zeo_client" in os.environ and "zeo_server" in os.environ:
        _print("conflicting options: --zeo_client and --zeo_server")
        sys.exit(1)
    instance_home = os.environ['INSTANCE_HOME']
    os.environ.setdefault('EVENT_LOG_FILE',
                          os.path.join(log_directory, 'zLOG.log'))
    os.environ.setdefault('EVENT_LOG_SEVERITY', '-300')
    # For numpy parallel-primitives such as numpy.dot() that is used in
    # testReceiptRecognition for example.
    os.environ.setdefault('OMP_NUM_THREADS', '3')

    _print("Loading Zope ... \n")
    _start = time.time()

    import Testing
    # the above import changes cfg.testinghome. Reset it to where our
    # custom_zodb.py can be found. This must be done before importing
    # ZopeTestCase below (Leo: I hate import side-effects with a passion).
    import App.config
    cfg = App.config.getConfiguration()
    # Zope do not call setDefaultBehaviors() for testing instance as it does for
    # a normal instance so `cfg.skip_ownership_checking = True` would not work
    # here...
    import AccessControl
    AccessControl.setDefaultBehaviors(
        # ownerous: ERP5 default (zope.conf: `skip-ownership-checking true`)
        False,
        # authenticated: Zope default (zope.conf: `skip_authentication_checking`)
        True,
        # verbose: Zope default
        False)
    cfg.testinghome = instance_home
    cfg.instancehome = instance_home
    from Zope2.Startup.datatypes import DBTab
    cfg.dbtab = DBTab({}, {})
    App.config.setConfiguration(cfg)

    if WIN:
        products_home = os.path.join(real_instance_home, 'Products')
        import Products
        Products.__path__.insert(0, products_home)
    else:
        products_home = os.path.join(instance_home, 'Products')

    from Testing.ZopeTestCase import layer, PortalTestCase, ZopeLite
    _apply_patches = layer._deferred_setup.pop(0)[0]
    assert _apply_patches.__name__ == '_apply_patches'

    # Set debug mode after importing ZopeLite that resets it to 0
    cfg.debug_mode = debug

    from ZConfig.components.logger import handlers, logger, loghandler
    import logging
    root_logger = logging.getLogger()
    # On recent Zope, ZopeTestCase does not have any logging facility.
    # So we must emulate the usual Zope startup code to catch log messages.
    from ZConfig.matcher import SectionValue
    section = SectionValue(
        {
            'dateformat': '%Y-%m-%d %H:%M:%S',
            'format':
            '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s',
            'level': logging.INFO,
            'path': os.environ['EVENT_LOG_FILE'],
            'max_size': None,
            'old_files': None,
            'when': None,
            'interval': None,
            'formatter': None,
        }, None, None)
    section.handlers = [handlers.FileHandlerFactory(section)]
    root_logger.handlers = []
    logger.EventLogFactory(section)()

    # Make sure that locally overridden python modules are used
    sys.path.insert(0, os.path.join(real_instance_home, 'lib', 'python'))

    # allow unit tests of our Products or business templates to be reached.
    sys.path += glob(os.path.join(products_home, '*', 'tests'))
    bt5_path_list = os.environ['erp5_tests_bt5_path'].split(',')
    bt5_path_list += [os.path.join(path, "*") for path in bt5_path_list]
    for path in bt5_path_list:
        path = os.path.join(path, '*', 'TestTemplateItem')
        sys.path += glob(path)
        sys.path += glob(os.path.join(path, 'portal_components'))

    sys.path += (os.path.join(real_instance_home,
                              'tests'), tests_home, instance_home)

    # change current directory to the test home, to create zLOG.log in this dir.
    os.chdir(tests_home)

    from Products.ERP5Type.patches import noZopeHelp
    from OFS.Application import AppInitializer
    AppInitializer.install_session_data_manager = lambda self: None

    # import ERP5TypeTestCase before calling layer.ZopeLite.setUp
    # XXX What if the unit test itself uses 'onsetup' ? We should be able to call
    #     remaining 'onsetup' hooks just before executing the test suite.
    from Products.ERP5Type.tests.ERP5TypeTestCase import \
        ProcessingNodeTestCase, ZEOServerTestCase, dummy_setUp, dummy_tearDown

    # Since we're not using the zope.testing testrunner, we need to set up
    # the layer ourselves
    # FIXME: We should start using Zope layers. Our setup will probably
    # be faster and we could drop most of this code we currently maintain
    # ourselves
    layer.ZopeLite.setUp()  # this will import custom_zodb.py

    def assertFalse():
        assert False

    layer.onsetup = assertFalse
    ZopeLite._theApp._p_jar.close()
    ZopeLite._theApp = None

    from Products.ERP5Type.tests.utils import DbFactory
    root_db_name, = cfg.dbtab.databases.keys()
    db_factory = DbFactory(root_db_name)
    db_factory.addMountPoint('/')

    TestRunner = unittest.TextTestRunner

    import Lifetime
    from Zope2.custom_zodb import Storage, save_mysql, \
        node_pid_list, neo_cluster, zeo_server_pid, wcfs_server

    def shutdown(signum, frame, signum_set=set()):
        Lifetime.shutdown(0)
        signum_set.add(signum)
        if node_pid_list is None and len(signum_set) > 1:
            # in case of ^C, a child should also receive a SIGHUP from the parent,
            # so we merge the first 2 different signals in a single exception
            signum_set.remove(signal.SIGHUP)
        else:
            raise KeyboardInterrupt

    if signal.getsignal(signal.SIGINT) is not signal.SIG_IGN:
        signal.signal(signal.SIGINT, shutdown)
    signal.signal(signal.SIGHUP, shutdown)

    coverage_config = os.environ.get('coverage', None)
    if coverage_config:
        coverage_process = coverage(config_file=coverage_config)
        coverage_process.start()

    try:
        save = int(os.environ.get('erp5_save_data_fs', 0))
        load = int(os.environ.get('erp5_load_data_fs', 0))
        dummy = save and (int(os.environ.get('update_business_templates', 0))
                          or not load)
        if zeo_server_pid == 0:
            suite = ZEOServerTestCase('asyncore_loop')
        elif node_pid_list is None or not test_list:
            suite = ProcessingNodeTestCase('processing_node')
            if not (dummy or load):
                _print(
                    'WARNING: either --save or --load should be used because static'
                    ' files are only reloaded by the node installing business'
                    ' templates.')
        else:
            if dummy:
                # Skip all tests and monkeypatch PortalTestCase to skip
                # afterSetUp/beforeTearDown.
                ERP5TypeTestLoader._testMethodPrefix = 'dummy_test'
                PortalTestCase.setUp = dummy_setUp
                PortalTestCase.tearDown = dummy_tearDown
            elif debug:
                # Hack the profiler to run only specified test methods,
                # and wrap results when running in debug mode.
                class DebugTextTestRunner(TestRunner):
                    def _makeResult(self):
                        result = super(DebugTextTestRunner, self)._makeResult()
                        return DebugTestResult(result)

                TestRunner = DebugTextTestRunner
            loader = ERP5TypeTestLoader()
            if run_only:
                ERP5TypeTestLoader.filter_test_list = [
                    re.compile(x).search for x in run_only.split(',')
                ]

            suite = loader.loadTestsFromNames(test_list)
            if run_only:
                ERP5TypeTestLoader.filter_test_list = None

        if node_pid_list is None:
            result = suite()
        else:
            if not test_list:
                root_logger.handlers.append(
                    loghandler.StreamHandler(sys.stderr))
            _print('done (%.3fs)\n' % (time.time() - _start))
            result = TestRunner(verbosity=verbosity).run(suite)
        transaction.commit()
    except:
        import traceback
        print "runUnitTestList Exception : %r" % (traceback.print_exc(), )
        # finally does not expect opened transaction, even in the
        # case of a Ctrl-C.
        transaction.abort()
        raise
    finally:
        ProcessingNodeTestCase.unregisterNode()
        db_factory.close()
        Storage.close()
        if node_pid_list is not None:
            # Wait that child processes exit. Stop ZEO storage (if any) after all
            # other nodes disconnected.
            for pid in node_pid_list:
                os.kill(pid, signal.SIGHUP)
            for pid in node_pid_list:
                os.waitpid(pid, 0)
            if zeo_server_pid:
                os.kill(zeo_server_pid, signal.SIGHUP)
                os.waitpid(zeo_server_pid, 0)
            if neo_cluster:
                neo_cluster.stop()
        if wcfs_server is not None:
            # Stop WCFS server (if any) after all Zope nodes are stopped and
            # disconnected from it.
            wcfs_server.stop()

    if coverage_config:
        coverage_process.stop()
        coverage_process.save()
        coverage_process.html_report()

    if save and save_mysql:
        save_mysql(verbosity)

    return result
Ejemplo n.º 4
0
def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
  if "zeo_client" in os.environ and "zeo_server" in os.environ:
    _print("conflicting options: --zeo_client and --zeo_server")
    sys.exit(1)
  instance_home =  os.environ['INSTANCE_HOME']
  os.environ.setdefault('EVENT_LOG_FILE', os.path.join(tests_home, 'zLOG.log'))
  os.environ.setdefault('EVENT_LOG_SEVERITY', '-300')

  _print("Loading Zope ... \n")
  _start = time.time()

  import Testing
  # the above import changes cfg.testinghome. Reset it to where our
  # custom_zodb.py can be found. This must be done before importing
  # ZopeTestCase below (Leo: I hate import side-effects with a passion).
  import App.config
  cfg = App.config.getConfiguration()
  cfg.testinghome = instance_home
  cfg.instancehome = instance_home
  from Zope2.Startup.datatypes import DBTab
  cfg.dbtab = DBTab({}, {})
  App.config.setConfiguration(cfg)

  if WIN:
    products_home = os.path.join(real_instance_home, 'Products')
    import Products
    Products.__path__.insert(0, products_home)
  else:
    products_home = os.path.join(instance_home, 'Products')

  from Testing.ZopeTestCase import layer, PortalTestCase, ZopeLite
  _apply_patches = layer._deferred_setup.pop(0)[0]
  assert _apply_patches.__name__ == '_apply_patches'

  from ZConfig.components.logger import handlers, logger, loghandler
  import logging
  root_logger = logging.getLogger()
  # On recent Zope, ZopeTestCase does not have any logging facility.
  # So we must emulate the usual Zope startup code to catch log messages.
  from ZConfig.matcher import SectionValue
  section = SectionValue({'dateformat': '%Y-%m-%d %H:%M:%S',
                          'format': '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s',
                          'level': logging.INFO,
                          'path': os.environ['EVENT_LOG_FILE'],
                          'max_size': None,
                          'old_files': None,
                          'when': None,
                          'interval': None,
                          'formatter': None,
                          },
                         None, None)
  section.handlers = [handlers.FileHandlerFactory(section)]
  root_logger.handlers = []
  logger.EventLogFactory(section)()

  # allow unit tests of our Products or business templates to be reached.
  product_test_list = glob(os.path.join(products_home, '*', 'tests'))
  sys.path.extend(product_test_list)
  erp5_tests_bt5_path = os.environ.get('erp5_tests_bt5_path',
                              os.path.join(instance_home, 'bt5'))
  bt5_path_list = erp5_tests_bt5_path.split(",")
  bt5_test_list = []
  project_bt5_test_list = []
  for bt5_path in bt5_path_list:
    bt5_test_list.extend(glob(os.path.join(bt5_path,'*','TestTemplateItem')))
    bt5_test_list.extend(glob(os.path.join(bt5_path,'*','TestTemplateItem',
                                           'portal_components')))

    # also suport instance_home/bt5/project_bt5/*
    project_bt5_test_list.extend(glob(os.path.join(bt5_path, '*', '*',
                                                   'TestTemplateItem')))
    project_bt5_test_list.extend(glob(os.path.join(bt5_path, '*', '*',
                                                   'TestTemplateItem',
                                                   'portal_components')))

  sys.path.extend(bt5_test_list)
  sys.path.extend(project_bt5_test_list)

  sys.path.extend((os.path.join(real_instance_home, 'tests'), tests_home))
  sys.path.append(instance_home)
  # Make sure that locally overridden python modules are used
  sys.path.insert(0, os.path.join(real_instance_home, 'lib', 'python'))

  # XXX Allowing to load modules from here is a wrong idea. use the above path
  # instead.
  # Add tests_framework_home as first path element.
  # this allows to bypass psyco by creating a dummy psyco module
  # it is then possible to run the debugger by "import pdb; pdb.set_trace()"
  sys.path.insert(0, tests_framework_home)

  # change current directory to the test home, to create zLOG.log in this dir.
  os.chdir(tests_home)

  from Products.ERP5Type.patches import noZopeHelp
  from OFS.Application import AppInitializer
  AppInitializer.install_session_data_manager = lambda self: None

  # import ERP5TypeTestCase before calling layer.ZopeLite.setUp
  # XXX What if the unit test itself uses 'onsetup' ? We should be able to call
  #     remaining 'onsetup' hooks just before executing the test suite.
  from Products.ERP5Type.tests.ERP5TypeTestCase import \
      ProcessingNodeTestCase, ZEOServerTestCase, dummy_setUp, dummy_tearDown

  # Since we're not using the zope.testing testrunner, we need to set up
  # the layer ourselves
  # FIXME: We should start using Zope layers. Our setup will probably
  # be faster and we could drop most of this code we currently maintain
  # ourselves
  layer.ZopeLite.setUp() # this will import custom_zodb.py
  def assertFalse():
    assert False
  layer.onsetup = assertFalse
  ZopeLite._theApp._p_jar.close()
  ZopeLite._theApp = None

  from Products.ERP5Type.tests.utils import DbFactory
  root_db_name, = cfg.dbtab.databases.keys()
  DbFactory(root_db_name).addMountPoint('/')

  TestRunner = backportUnittest.TextTestRunner

  import Lifetime
  from Zope2.custom_zodb import Storage, save_mysql, \
      node_pid_list, neo_cluster, zeo_server_pid
  def shutdown(signum, frame, signum_set=set()):
    Lifetime.shutdown(0)
    signum_set.add(signum)
    if node_pid_list is None and len(signum_set) > 1:
      # in case of ^C, a child should also receive a SIGHUP from the parent,
      # so we merge the first 2 different signals in a single exception
      signum_set.remove(signal.SIGHUP)
    else:
      raise KeyboardInterrupt
  if signal.getsignal(signal.SIGINT) is not signal.SIG_IGN:
    signal.signal(signal.SIGINT, shutdown)
  signal.signal(signal.SIGHUP, shutdown)

  coverage_config = os.environ.get('coverage', None)
  if coverage_config:
    coverage_process = coverage(config_file=coverage_config)
    coverage_process.start()

  try:
    save = int(os.environ.get('erp5_save_data_fs', 0))
    load = int(os.environ.get('erp5_load_data_fs', 0))
    dummy = save and (int(os.environ.get('update_business_templates', 0))
                      or not load)
    if zeo_server_pid == 0:
      suite = ZEOServerTestCase('asyncore_loop')
    elif node_pid_list is None or not test_list:
      suite = ProcessingNodeTestCase('processing_node')
      if not (dummy or load):
        _print('WARNING: either --save or --load should be used because static'
               ' files are only reloaded by the node installing business'
               ' templates.')
    else:
      if dummy:
        # Skip all tests and monkeypatch PortalTestCase to skip
        # afterSetUp/beforeTearDown.
        ERP5TypeTestLoader._testMethodPrefix = 'dummy_test'
        PortalTestCase.setUp = dummy_setUp
        PortalTestCase.tearDown = dummy_tearDown
      elif debug:
        # Hack the profiler to run only specified test methods,
        # and wrap results when running in debug mode.
        class DebugTextTestRunner(TestRunner):
          def _makeResult(self):
            result = super(DebugTextTestRunner, self)._makeResult()
            return DebugTestResult(result)
        TestRunner = DebugTextTestRunner
      loader = ERP5TypeTestLoader()
      if run_only:
        ERP5TypeTestLoader.filter_test_list = [re.compile(x).search for x in
            run_only.split(',')]

      suite = loader.loadTestsFromNames(test_list)
      if run_only:
        ERP5TypeTestLoader.filter_test_list = None

    if node_pid_list is None:
      result = suite()
    else:
      if not test_list:
        root_logger.handlers.append(loghandler.StreamHandler(sys.stderr))
      _print('done (%.3fs)\n' % (time.time() - _start))
      result = TestRunner(verbosity=verbosity).run(suite)
    transaction.commit()
  except:
    import traceback
    print "runUnitTestList Exception : %r" % (traceback.print_exc(),)
    # finally does not expect opened transaction, even in the
    # case of a Ctrl-C.
    transaction.abort()
    raise
  finally:
    ProcessingNodeTestCase.unregisterNode()
    Storage.close()
    if node_pid_list is not None:
      # Wait that child processes exit. Stop ZEO storage (if any) after all
      # other nodes disconnected.
      for pid in node_pid_list:
        os.kill(pid, signal.SIGHUP)
      for pid in node_pid_list:
        os.waitpid(pid, 0)
      if zeo_server_pid:
        os.kill(zeo_server_pid, signal.SIGHUP)
        os.waitpid(zeo_server_pid, 0)
      if neo_cluster:
        neo_cluster.stop()

  if coverage_config:
    coverage_process.stop()
    coverage_process.save()
    coverage_process.html_report()

  if save:
    os.chdir(instance_home)
    if save_mysql:
      save_mysql(verbosity)
    if suite.__class__ not in (ProcessingNodeTestCase, ZEOServerTestCase):
      # Static files are modified by the node installing business templates,
      # i.e. by the node running the unit test. There is no point saving them
      # on a ZEO server, or on nodes that only process activities: this has to
      # be done manually.
      if verbosity:
        _print('Dumping static files...\n')
      live_instance_path = os.environ.get('live_instance_path')
      for static_dir in static_dir_list:
        if os.path.islink(static_dir):
          continue
        if live_instance_path:
          backup_path = os.path.join(live_instance_path, static_dir)
        else:
          backup_path = static_dir + '.bak'
        try:
          shutil.rmtree(backup_path)
        except OSError, e:
          if e.errno != errno.ENOENT:
            raise
        os.rename(static_dir, backup_path)
    elif node_pid_list is not None:
      _print('WARNING: No static files saved. You will have to do it manually.')