From 4718f5e11be8f2541dc8f6876cd60aa03d0edc76 Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Wed, 2 Jan 2013 18:39:50 +0100 Subject: [PATCH] Fix runUnitTest for Zope 2.13 by disabling ZopeLite patches A ZopeLite patch was added to prevent loading of zcml files, which is wrong for ERP5: CMF products were not properly initialized. Code is also simpler now that we call OFS.Application.initialize(), which is not significantly slower. We keep patch not to register help though because this is quite expensive: we should even consider always disable help because they seems to cause many conflicts during Zope cluster startup. A monkey-patch to unittest is updated for Python 2.7, so that tests aren't run when they shouldn't (e.g. --save without --load). --- product/ERP5OOo/tests/testOOoImport.py | 4 - product/ERP5Type/patches/noZopeHelp.py | 25 +++++ product/ERP5Type/tests/ERP5TypeTestCase.py | 94 ------------------- .../ERP5Type/tests/ProcessingNodeTestCase.py | 3 + product/ERP5Type/tests/runUnitTest.py | 14 +-- 5 files changed, 36 insertions(+), 104 deletions(-) create mode 100644 product/ERP5Type/patches/noZopeHelp.py diff --git a/product/ERP5OOo/tests/testOOoImport.py b/product/ERP5OOo/tests/testOOoImport.py index 8d6d0993e0..21a7a71fd6 100644 --- a/product/ERP5OOo/tests/testOOoImport.py +++ b/product/ERP5OOo/tests/testOOoImport.py @@ -30,18 +30,14 @@ import unittest import os -from Testing import ZopeTestCase from AccessControl.SecurityManagement import newSecurityManager from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase -from Products.ERP5Type.tests.ERP5TypeTestCase import install_product_quiet from Products.ERP5Type.tests.ERP5TypeTestCase import _getConversionServerDict from Products.ERP5Type.tests.Sequence import SequenceList from Products.ERP5OOo.OOoUtils import OOoParser from Products.ERP5Form.PreferenceTool import Priority from DateTime import DateTime -ZopeTestCase.installProduct('Sessions', quiet=install_product_quiet) - class FileUploadTest(file): __allow_access_to_unprotected_subobjects__=1 diff --git a/product/ERP5Type/patches/noZopeHelp.py b/product/ERP5Type/patches/noZopeHelp.py new file mode 100644 index 0000000000..0d558c1c32 --- /dev/null +++ b/product/ERP5Type/patches/noZopeHelp.py @@ -0,0 +1,25 @@ +############################################################################## +# +# Copyright (c) 2005 Zope Foundation and Contributors. +# Copyright (c) 2013 Nexedi SARL and Contributors. All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## + +# copied & pasted from Testing.ZopeTestCase.ZopeLite +import App.ProductContext + +if 1: + # Avoid expensive help registration + def null_register_topic(self,id,topic): pass + App.ProductContext.ProductContext.registerHelpTopic = null_register_topic + def null_register_title(self,title): pass + App.ProductContext.ProductContext.registerHelpTitle = null_register_title + def null_register_help(self,directory='',clear=1,title_re=None): pass + App.ProductContext.ProductContext.registerHelp = null_register_help diff --git a/product/ERP5Type/tests/ERP5TypeTestCase.py b/product/ERP5Type/tests/ERP5TypeTestCase.py index 4f3b214af3..6484fd9b96 100644 --- a/product/ERP5Type/tests/ERP5TypeTestCase.py +++ b/product/ERP5Type/tests/ERP5TypeTestCase.py @@ -65,8 +65,6 @@ from zLOG import LOG, DEBUG from Products.ERP5Type.tests.backportUnittest import SetupSiteError from Products.ERP5Type.tests.utils import DummyMailHostMixin, parseListeningAddress -# Quiet messages when installing products -install_product_quiet = 1 # Quiet messages when installing business templates install_bt5_quiet = 0 @@ -79,37 +77,11 @@ if getattr(config, 'product_config', None) is None: config.product_config = {} config.product_config['deadlockdebugger'] = {'dump_url':'/manage_debug_threads'} -import OFS.Application -OFS.Application.import_products() - -# Std Zope Products -ZopeTestCase.installProduct('Photo', quiet=install_product_quiet) -ZopeTestCase.installProduct('Formulator', quiet=install_product_quiet) -ZopeTestCase.installProduct('FCKeditor', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZSQLMethods', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZMySQLDA', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZSQLCatalog', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZMailIn', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZGDChart', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZCTextIndex', quiet=install_product_quiet) -ZopeTestCase.installProduct('MailHost', quiet=install_product_quiet) -ZopeTestCase.installProduct('PageTemplates', quiet=install_product_quiet) -ZopeTestCase.installProduct('PythonScripts', quiet=install_product_quiet) -ZopeTestCase.installProduct('ExternalMethod', quiet=install_product_quiet) -ZopeTestCase.installProduct('Sessions', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZODBMountPoint', quiet=install_product_quiet) - from Testing.ZopeTestCase.layer import onsetup -# installProduct() is a delayed call, so imports that depend on products being -# "initialize"d should only be called "on setup". The decorator above delays -# calls to the decorated function until after Product initialization. -# Also, we need Five to wire all our CMF dependencies. -ZopeTestCase.installProduct('Five', quiet=install_product_quiet) try: # Workaround iHotFix patch that doesn't work with # ZopeTestCase REQUESTs - ZopeTestCase.installProduct('iHotfix', quiet=install_product_quiet) from Products import iHotfix from types import UnicodeType # revert monkey patchs from iHotfix @@ -126,7 +98,6 @@ try: iHotfix.iHotfixStringIO = UnicodeSafeStringIO except ImportError: pass -ZopeTestCase.installProduct('Localizer', quiet=install_product_quiet) try: # Workaround Localizer >= 1.2 patch that doesn't work with # ZopeTestCase REQUESTs (it's the same as iHotFix @@ -137,75 +108,10 @@ try: except ImportError: pass -try: - from Products.Localizer import patches - # originalStringIO has been removed from recent Localizer versions - from Products.Localizer.patches import originalStringIO - class UnicodeSafeStringIO(patches.originalStringIO): - """StringIO like class which never fails with unicode.""" - def write(self, s): - if isinstance(s, unicode): - s = s.encode('utf8', 'repr') - patches.originalStringIO.write(self, s) - # Localizer will patch PageTemplate StringIO with - patches.LocalizerStringIO = UnicodeSafeStringIO -except ImportError: - pass - from Products.ERP5Type.tests.ProcessingNodeTestCase import \ ProcessingNodeTestCase, patchActivityTool onsetup(patchActivityTool)() -ZopeTestCase.installProduct('TimerService', quiet=install_product_quiet) - -# CMF -ZopeTestCase.installProduct('CMFCore', quiet=install_product_quiet) -ZopeTestCase.installProduct('CMFDefault', quiet=install_product_quiet) -ZopeTestCase.installProduct('CMFTopic', quiet=install_product_quiet) -ZopeTestCase.installProduct('DCWorkflow', quiet=install_product_quiet) -ZopeTestCase.installProduct('CMFCalendar', quiet=install_product_quiet) - -# Based on CMF -ZopeTestCase.installProduct('CMFPhoto', quiet=install_product_quiet) -ZopeTestCase.installProduct('BTreeFolder2', quiet=install_product_quiet) -ZopeTestCase.installProduct('CMFReportTool', quiet=install_product_quiet) # Not required by ERP5Type but required by ERP5Form -ZopeTestCase.installProduct('TranslationService', quiet=install_product_quiet) -ZopeTestCase.installProduct('PortalTransforms', quiet=install_product_quiet) -ZopeTestCase.installProduct('MimetypesRegistry', quiet=install_product_quiet) - -# Security Stuff -ZopeTestCase.installProduct('PluggableAuthService', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5Security', quiet=install_product_quiet) - -# Debugging -ZopeTestCase.installProduct('VerboseSecurity', quiet=install_product_quiet) -ZopeTestCase.installProduct('Zelenium', quiet=install_product_quiet) - -# ERP5 - ERP5Type product is installed last so that -# initializeProductDocumentRegistry is only called -# after all products which need to register their Document -# classes can register them by invoking updateGlobals in __init__ -ZopeTestCase.installProduct('CMFActivity', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5Catalog', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5Form', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5SyncML', quiet=install_product_quiet) -ZopeTestCase.installProduct('ERP5Type', quiet=install_product_quiet) -ZopeTestCase.installProduct('CMFCategory', quiet=install_product_quiet) -ZopeTestCase.installProduct('ZMySQLDDA', quiet=install_product_quiet) - -ZopeTestCase.installProduct('ParsedXML', quiet=install_product_quiet) - -# Install everything else which looks like related to ERP5 -from OFS.Application import get_products -for priority, product_name, index, product_dir in get_products(): - # XXX very heuristic - if os.path.isdir(os.path.join(product_dir, product_name, 'Document')) \ - or os.path.isdir(os.path.join(product_dir, product_name, 'PropertySheet')) \ - or os.path.isdir(os.path.join(product_dir, product_name, 'Constraint')) \ - or os.path.isdir(os.path.join(product_dir, product_name, 'Tool')): - ZopeTestCase.installProduct(product_name, quiet=install_product_quiet) - from AccessControl.SecurityManagement import newSecurityManager, noSecurityManager from Acquisition import aq_base diff --git a/product/ERP5Type/tests/ProcessingNodeTestCase.py b/product/ERP5Type/tests/ProcessingNodeTestCase.py index e76caad0b4..0c19982fb6 100644 --- a/product/ERP5Type/tests/ProcessingNodeTestCase.py +++ b/product/ERP5Type/tests/ProcessingNodeTestCase.py @@ -101,6 +101,9 @@ def Application_resolveConflict(self, old_state, saved_state, new_state): new_state = new_state.copy() old, saved, new = [set(state.pop('test_processing_nodes', {}).items()) for state in old_state, saved_state, new_state] + # The value of these attributes don't have proper __eq__ implementation. + for attr in '__before_traverse__', '__before_publishing_traverse__': + del old_state[attr], saved_state[attr] if sorted(old_state.items()) != sorted(saved_state.items()): raise ConflictError new |= saved - old diff --git a/product/ERP5Type/tests/runUnitTest.py b/product/ERP5Type/tests/runUnitTest.py index 215049c92b..4c2843681a 100755 --- a/product/ERP5Type/tests/runUnitTest.py +++ b/product/ERP5Type/tests/runUnitTest.py @@ -322,7 +322,8 @@ class ERP5TypeTestLoader(unittest.TestLoader): return filtered_name_list return name_list -unittest.TestLoader = ERP5TypeTestLoader +# BBB: Python < 2.7 +getattr(unittest, 'loader', unittest).TestLoader = ERP5TypeTestLoader class DebugTestResult: """Wrap an unittest.TestResult, invoking pdb on errors / failures @@ -393,8 +394,9 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): else: products_home = os.path.join(instance_home, 'Products') - import OFS.Application - from Testing import ZopeTestCase + from Testing.ZopeTestCase import layer, PortalTestCase + _apply_patches = layer._deferred_setup.pop(0)[0] + assert _apply_patches.__name__ == '_apply_patches' from ZConfig.components.logger import handlers, logger, loghandler import logging @@ -448,12 +450,12 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): # change current directory to the test home, to create zLOG.log in this dir. os.chdir(tests_home) + from Products.ERP5Type.patches import noZopeHelp # 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 - from Testing.ZopeTestCase import layer # Since we're not using the zope.testing testrunner, we need to set up # the layer ourselves @@ -510,8 +512,8 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): # Skip all tests and monkeypatch PortalTestCase to skip # afterSetUp/beforeTearDown. ERP5TypeTestLoader._testMethodPrefix = 'dummy_test' - ZopeTestCase.PortalTestCase.setUp = dummy_setUp - ZopeTestCase.PortalTestCase.tearDown = dummy_tearDown + 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. -- 2.30.9