Commit 54683e0c authored by Jérome Perrin's avatar Jérome Perrin

new --processing_node_loop=timerserver argument for runUnitTest

and several small fixes or changes to make this easier

See merge request nexedi/erp5!1642
parents 123635b9 61e8a9ce
...@@ -26,7 +26,6 @@ from cPickle import dumps ...@@ -26,7 +26,6 @@ from cPickle import dumps
from glob import glob from glob import glob
from hashlib import md5 from hashlib import md5
from warnings import warn from warnings import warn
from ExtensionClass import pmc_init_of
from DateTime import DateTime from DateTime import DateTime
import Products.ZMySQLDA.DA import Products.ZMySQLDA.DA
from Products.ZMySQLDA.DA import Connection as ZMySQLDA_Connection from Products.ZMySQLDA.DA import Connection as ZMySQLDA_Connection
...@@ -65,7 +64,7 @@ from zLOG import LOG, DEBUG ...@@ -65,7 +64,7 @@ from zLOG import LOG, DEBUG
from Products.ERP5Type.Utils import convertToUpperCase from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.tests.backportUnittest import SetupSiteError from Products.ERP5Type.tests.backportUnittest import SetupSiteError
from Products.ERP5Type.tests.utils import addUserToDeveloperRole from Products.ERP5Type.tests.utils import addUserToDeveloperRole
from Products.ERP5Type.tests.utils import DummyMailHostMixin, parseListeningAddress from Products.ERP5Type.tests.utils import parseListeningAddress
# Quiet messages when installing business templates # Quiet messages when installing business templates
install_bt5_quiet = 0 install_bt5_quiet = 0
...@@ -354,23 +353,6 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase): ...@@ -354,23 +353,6 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase):
if not uf.getUserById(user_name): if not uf.getUserById(user_name):
uf._doAddUser(user_name, self.newPassword(), ['Member'], []) uf._doAddUser(user_name, self.newPassword(), ['Member'], [])
def _setUpDummyMailHost(self):
"""Replace Original Mail Host by Dummy Mail Host in a non-persistent way
"""
cls = self.portal.MailHost.__class__
if not issubclass(cls, DummyMailHostMixin):
cls.__bases__ = (DummyMailHostMixin,) + cls.__bases__
pmc_init_of(cls)
def _restoreMailHost(self):
"""Restore original Mail Host
"""
if self.portal is not None:
cls = self.portal.MailHost.__class__
if cls.__bases__[0] is DummyMailHostMixin:
cls.__bases__ = cls.__bases__[1:]
pmc_init_of(cls)
def pinDateTime(self, date_time): def pinDateTime(self, date_time):
# pretend time has stopped at a certain date (i.e. the test runs # pretend time has stopped at a certain date (i.e. the test runs
# infinitely fast), for example to avoid errors on tests that are started # infinitely fast), for example to avoid errors on tests that are started
...@@ -1593,7 +1575,7 @@ class ZEOServerTestCase(ERP5TypeTestCase): ...@@ -1593,7 +1575,7 @@ class ZEOServerTestCase(ERP5TypeTestCase):
pass pass
def tearDown(self): def tearDown(self):
self.zeo_server.close_server() self.zeo_server.close()
class lazy_func_prop(object): class lazy_func_prop(object):
......
...@@ -9,8 +9,9 @@ from Testing import ZopeTestCase ...@@ -9,8 +9,9 @@ from Testing import ZopeTestCase
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
from zLOG import LOG, ERROR from zLOG import LOG, ERROR
from Products.CMFActivity.Activity.Queue import VALIDATION_ERROR_DELAY from Products.CMFActivity.Activity.Queue import VALIDATION_ERROR_DELAY
from ExtensionClass import pmc_init_of
from Products.ERP5Type.tests.utils import \ from Products.ERP5Type.tests.utils import \
addUserToDeveloperRole, createZServer, parseListeningAddress addUserToDeveloperRole, createZServer, DummyMailHostMixin, parseListeningAddress
from Products.CMFActivity.ActivityTool import getCurrentNode from Products.CMFActivity.ActivityTool import getCurrentNode
...@@ -334,7 +335,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase): ...@@ -334,7 +335,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
This aborts current transaction. This aborts current transaction.
""" """
for i in xrange(30): for i in xrange(60):
node_list = list(self.portal.portal_activities.getProcessingNodeList()) node_list = list(self.portal.portal_activities.getProcessingNodeList())
if len(node_list) >= node_count: if len(node_list) >= node_count:
node_list.remove(getCurrentNode()) node_list.remove(getCurrentNode())
...@@ -354,6 +355,23 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase): ...@@ -354,6 +355,23 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
self._registerNode(distributing=not cluster, processing=1) self._registerNode(distributing=not cluster, processing=1)
self.commit() self.commit()
def _setUpDummyMailHost(self):
"""Replace Original Mail Host by Dummy Mail Host in a non-persistent way
"""
cls = self.portal.MailHost.__class__
if not issubclass(cls, DummyMailHostMixin):
cls.__bases__ = (DummyMailHostMixin,) + cls.__bases__
pmc_init_of(cls)
def _restoreMailHost(self):
"""Restore original Mail Host
"""
if self.portal is not None:
cls = self.portal.MailHost.__class__
if cls.__bases__[0] is DummyMailHostMixin:
cls.__bases__ = cls.__bases__[1:]
pmc_init_of(cls)
def processing_node(self): def processing_node(self):
"""Main loop for nodes that process activities""" """Main loop for nodes that process activities"""
try: try:
...@@ -361,9 +379,10 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase): ...@@ -361,9 +379,10 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
time.sleep(.3) time.sleep(.3)
transaction.begin() transaction.begin()
try: try:
portal = self.app[self.app.test_portal_name] portal = self.portal = self.app[self.app.test_portal_name]
except (AttributeError, KeyError): except (AttributeError, KeyError):
continue continue
self._setUpDummyMailHost()
if portal.portal_activities.isSubscribed(): if portal.portal_activities.isSubscribed():
try: try:
portal.portal_activities.process_timer(None, None) portal.portal_activities.process_timer(None, None)
...@@ -371,3 +390,26 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase): ...@@ -371,3 +390,26 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
LOG('Invoking Activity Tool', ERROR, '', error=True) LOG('Invoking Activity Tool', ERROR, '', error=True)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
def timerserver(self):
"""Main loop using timer server.
"""
import Products.TimerService
timerserver_thread = None
try:
while not Lifetime._shutdown_phase:
time.sleep(.3)
transaction.begin()
try:
self.portal = self.app[self.app.test_portal_name]
except (AttributeError, KeyError):
continue
self._setUpDummyMailHost()
if not timerserver_thread:
timerserver_thread = Products.TimerService.timerserver.TimerServer.TimerServer(
module='Zope2',
interval=0.1,
)
except KeyboardInterrupt:
pass
...@@ -141,8 +141,18 @@ Options: ...@@ -141,8 +141,18 @@ Options:
activities. activities.
--zeo_server=[[HOST:]PORT] Bind the ZEO server to the given host/port. --zeo_server=[[HOST:]PORT] Bind the ZEO server to the given host/port.
--zeo_client=[HOST:]PORT Use specified ZEO server as storage. --zeo_client=[HOST:]PORT Use specified ZEO server as storage.
--processing_node_loop=LOOP
Make ZEO clients execute the given loop, one of:
- processing_node: process activities only.
this is the default.
- timerserver: start a timer server thread,
which will typically execute activities,
alarms and everything else registered on
timer service.
This option only makes sense with --activity_node=
or when not specifying a test to run.
--zserver=ADDRESS[,...] Make ZServer listen on given IPv4 address. --zserver=ADDRESS[,...] Make ZServer listen on given IPv4 address.
Adresses can be given in the following syntaxs: Addresses can be given in the following syntaxs:
- HOST:PORT - HOST:PORT
- PORT in this case, host will be 127.0.0.1 - PORT in this case, host will be 127.0.0.1
- HOST in this case a free port will be assigned - HOST in this case a free port will be assigned
...@@ -492,7 +502,7 @@ _print = sys.stderr.write ...@@ -492,7 +502,7 @@ _print = sys.stderr.write
def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
if "zeo_client" in os.environ and "zeo_server" in os.environ: if "zeo_client" in os.environ and "zeo_server" in os.environ:
_print("conflicting options: --zeo_client and --zeo_server") _print("conflicting options: --zeo_client and --zeo_server\n")
sys.exit(1) sys.exit(1)
instance_home = os.environ['INSTANCE_HOME'] instance_home = os.environ['INSTANCE_HOME']
os.environ.setdefault('EVENT_LOG_FILE', os.path.join(log_directory, 'zLOG.log')) os.environ.setdefault('EVENT_LOG_FILE', os.path.join(log_directory, 'zLOG.log'))
...@@ -547,8 +557,11 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): ...@@ -547,8 +557,11 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
# On recent Zope, ZopeTestCase does not have any logging facility. # On recent Zope, ZopeTestCase does not have any logging facility.
# So we must emulate the usual Zope startup code to catch log messages. # So we must emulate the usual Zope startup code to catch log messages.
from ZConfig.matcher import SectionValue from ZConfig.matcher import SectionValue
logging_format = '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s'
if os.environ.get('activity_node'):
logging_format = '%(process)d ' + logging_format
section = SectionValue({'dateformat': '%Y-%m-%d %H:%M:%S', section = SectionValue({'dateformat': '%Y-%m-%d %H:%M:%S',
'format': '%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s', 'format': logging_format,
'level': logging.INFO, 'level': logging.INFO,
'path': os.environ['EVENT_LOG_FILE'], 'path': os.environ['EVENT_LOG_FILE'],
'max_size': None, 'max_size': None,
...@@ -638,11 +651,12 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): ...@@ -638,11 +651,12 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
if zeo_server_pid == 0: if zeo_server_pid == 0:
suite = ZEOServerTestCase('asyncore_loop') suite = ZEOServerTestCase('asyncore_loop')
elif node_pid_list is None or not test_list: elif node_pid_list is None or not test_list:
suite = ProcessingNodeTestCase('processing_node') processing_node_loop = os.environ.get('processing_node_loop', 'processing_node')
suite = ProcessingNodeTestCase(processing_node_loop)
if not (dummy or load): if not (dummy or load):
_print('WARNING: either --save or --load should be used because static' _print('WARNING: either --save or --load should be used because static'
' files are only reloaded by the node installing business' ' files are only reloaded by the node installing business'
' templates.') ' templates.\n')
else: else:
if dummy: if dummy:
# Skip all tests and monkeypatch PortalTestCase to skip # Skip all tests and monkeypatch PortalTestCase to skip
...@@ -668,7 +682,7 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): ...@@ -668,7 +682,7 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
ERP5TypeTestLoader.filter_test_list = None ERP5TypeTestLoader.filter_test_list = None
if node_pid_list is None: if node_pid_list is None:
result = suite() result = suite.debug()
else: else:
if not test_list: if not test_list:
root_logger.handlers.append(loghandler.StreamHandler(sys.stderr)) root_logger.handlers.append(loghandler.StreamHandler(sys.stderr))
...@@ -763,6 +777,7 @@ def main(argument_list=None): ...@@ -763,6 +777,7 @@ def main(argument_list=None):
"live_instance=", "live_instance=",
"zeo_client=", "zeo_client=",
"zeo_server=", "zeo_server=",
"processing_node_loop=",
"zserver=", "zserver=",
"zserver_frontend_url=", "zserver_frontend_url=",
"neo_storage", "neo_storage",
...@@ -878,6 +893,8 @@ def main(argument_list=None): ...@@ -878,6 +893,8 @@ def main(argument_list=None):
os.environ["zeo_client"] = arg os.environ["zeo_client"] = arg
elif opt == "--zeo_server": elif opt == "--zeo_server":
os.environ["zeo_server"] = arg os.environ["zeo_server"] = arg
elif opt == "--processing_node_loop":
os.environ["processing_node_loop"] = arg
elif opt == "--zserver": elif opt == "--zserver":
os.environ["zserver"] = arg os.environ["zserver"] = arg
elif opt == "--zserver_frontend_url": elif opt == "--zserver_frontend_url":
......
...@@ -65,7 +65,7 @@ class TimerServer(threading.Thread): ...@@ -65,7 +65,7 @@ class TimerServer(threading.Thread):
_module_name=module_name, _module_name=module_name,
_request=request, _request=request,
_response=response) _response=response)
server.add_task(self) server.task_dispatcher.add_task(self)
def cancel(self): def cancel(self):
pass pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment