Commit 43d789d7 authored by Kirill Smelkov's avatar Kirill Smelkov

tests: Teach test driver to pass testWendelinCore when run with wendelin.core 2

This is follow-up to 5796a17a (core_test: Add test to make sure that
wendelin.core basically works; nexedi/erp5!1429).

In that commit it was said that testWendelinCore

    "currently passes with wendelin.core 1, which is the default.
     It also passes as live test with wendelin.core 2.
     However with wendelin.core 2 it currently fails when run on testnodes
     ...
     because we need to amend ERP5 test driver

     1. to run tests on a real storage instead of in-RAM Mapping Storage(*), and
     2. to spawn WCFS server for each such storage."

This patch addresses that latter problem to run testWendelinCore under
testnode infrastructure.

@rafael and @jerome suggested that we can force a test to be run on a
real storage via `runUnitTest --load --save` or via `--activity_node=n`.

@rafael also suggested not to generally change the testing driver, but instead
make step-by-step progress and first tag each test that uses wendelin.core with an
option. Let's go this way now: runUnitTest/custom_zodb are taught to launch
WCFS server if wendelin.core usage is requested and software is built with
wendelin.core 2.

With both changes combined testWendelinCore should now pass OK when run
on a testnode with both wendelin.core 1 and wendelin.core 2.

This patch is based on a draft patch by @rafael: https://lab.nexedi.com/rafael/erp5/commit/14e3a777.

This patch also relies on recent wendelin.core 2 wcfs.py rework which
exposed functionality to start WCFS server and to further control it:
wendelin.core@5bfa8cf8.

/cc @tomo, @romain, @jerome, @seb
parent ea4cb55b
...@@ -29,6 +29,7 @@ except KeyError: ...@@ -29,6 +29,7 @@ except KeyError:
data_fs_path = os.environ.get('erp5_tests_data_fs_path', data_fs_path = os.environ.get('erp5_tests_data_fs_path',
os.path.join(instance_home, 'var', 'Data.fs')) os.path.join(instance_home, 'var', 'Data.fs'))
with_wendelin_core = int(os.environ.get('with_wendelin.core', 0))
load = int(os.environ.get('erp5_load_data_fs', 0)) load = int(os.environ.get('erp5_load_data_fs', 0))
save = int(os.environ.get('erp5_save_data_fs', 0)) save = int(os.environ.get('erp5_save_data_fs', 0))
save_mysql = int(os.environ.get('erp5_dump_sql') or not zeo_client) or None save_mysql = int(os.environ.get('erp5_dump_sql') or not zeo_client) or None
...@@ -83,12 +84,16 @@ else: ...@@ -83,12 +84,16 @@ else:
zeo_server_pid = None zeo_server_pid = None
node_pid_list = [] node_pid_list = []
in_forked_process = False
def fork(): def fork():
global in_forked_process
pid = os.fork() pid = os.fork()
if pid: if pid:
# make sure parent and child have 2 different RNG # make sure parent and child have 2 different RNG
instance_random.seed(instance_random.random()) instance_random.seed(instance_random.random())
else:
in_forked_process = True
return pid return pid
def forkNodes(): def forkNodes():
...@@ -173,5 +178,18 @@ else: ...@@ -173,5 +178,18 @@ else:
except TypeError: # BBB: ZEO<5 except TypeError: # BBB: ZEO<5
Storage = ClientStorage(zeo_client) Storage = ClientStorage(zeo_client)
# launch WCFS server if wendelin.core usage is requested and we are running
# with wendelin.core 2.
wcfs_server = None
if with_wendelin_core and not in_forked_process:
try:
from wendelin import wcfs
except ImportError:
pass # wendelin.core 1
else:
from wendelin.lib.zodb import zstor_2zurl
zurl = zstor_2zurl(Storage)
wcfs_server = wcfs.start(zurl)
if node_pid_list is not None: if node_pid_list is not None:
_print("Instance at %r loaded ... " % instance_home) _print("Instance at %r loaded ... " % instance_home)
...@@ -159,6 +159,8 @@ Options: ...@@ -159,6 +159,8 @@ Options:
extend sys.path extend sys.path
--instance_home=PATH Create/use test instance in given path --instance_home=PATH Create/use test instance in given path
--log_directory=PATH Create log files in given path --log_directory=PATH Create log files in given path
--with_wendelin.core Pass for tests that use wendelin.core.
This option is likely to become a noop in the future.
When no unit test is specified, only activities are processed. When no unit test is specified, only activities are processed.
""" """
...@@ -608,7 +610,7 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): ...@@ -608,7 +610,7 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
import Lifetime import Lifetime
from Zope2.custom_zodb import Storage, save_mysql, \ from Zope2.custom_zodb import Storage, save_mysql, \
node_pid_list, neo_cluster, zeo_server_pid node_pid_list, neo_cluster, zeo_server_pid, wcfs_server
def shutdown(signum, frame, signum_set=set()): def shutdown(signum, frame, signum_set=set()):
Lifetime.shutdown(0) Lifetime.shutdown(0)
signum_set.add(signum) signum_set.add(signum)
...@@ -694,6 +696,10 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None): ...@@ -694,6 +696,10 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
os.waitpid(zeo_server_pid, 0) os.waitpid(zeo_server_pid, 0)
if neo_cluster: if neo_cluster:
neo_cluster.stop() 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: if coverage_config:
coverage_process.stop() coverage_process.stop()
...@@ -761,7 +767,8 @@ def main(argument_list=None): ...@@ -761,7 +767,8 @@ def main(argument_list=None):
"products_path=", "products_path=",
"sys_path=", "sys_path=",
"instance_home=", "instance_home=",
"log_directory=" "log_directory=",
"with_wendelin.core"
]) ])
except getopt.GetoptError, msg: except getopt.GetoptError, msg:
usage(sys.stderr, msg) usage(sys.stderr, msg)
...@@ -883,6 +890,8 @@ def main(argument_list=None): ...@@ -883,6 +890,8 @@ def main(argument_list=None):
instance_home = os.path.abspath(arg) instance_home = os.path.abspath(arg)
elif opt == "--log_directory": elif opt == "--log_directory":
_log_directory = os.path.abspath(arg) _log_directory = os.path.abspath(arg)
elif opt == "--with_wendelin.core":
os.environ["with_wendelin.core"] = "1"
bt5_path_list += filter(None, bt5_path_list += filter(None,
os.environ.get("erp5_tests_bt5_path", "").split(',')) os.environ.get("erp5_tests_bt5_path", "").split(','))
......
# -*- coding: utf-8 -*-
from glob import glob from glob import glob
import os, subprocess, re import os, subprocess, re
# test_suite is provided by 'run_test_suite' # test_suite is provided by 'run_test_suite'
...@@ -89,6 +90,19 @@ class ERP5(_ERP5): ...@@ -89,6 +90,19 @@ class ERP5(_ERP5):
if not status_dict['status_code']: if not status_dict['status_code']:
status_dict = self.runUnitTest('--load', '--activity_node=2', full_test) status_dict = self.runUnitTest('--load', '--activity_node=2', full_test)
return status_dict return status_dict
elif test.startswith('testWendelinCore'):
# Combining Zope and WCFS working together requires data to be on a real
# storage, not on in-RAM MappingStorage inside Zope's Python process.
# Force this via --load --save for now.
#
# Also manually indicate via --with-wendelin_core, that this test needs
# WCFS server - corresponding to ZODB test storage - to be launched.
#
# In the future we might want to rework custom_zodb.py to always use
# FileStorage on tmpfs instead of δ=MappingStorage in DemoStorage(..., δ),
# and to always spawn WCFS for all tests, so that this hack becomes
# unnecessary.
return self.runUnitTest('--load', '--save', '--with_wendelin.core', full_test)
elif test.startswith('testFunctional'): elif test.startswith('testFunctional'):
return self._updateFunctionalTestResponse(self.runUnitTest(full_test)) return self._updateFunctionalTestResponse(self.runUnitTest(full_test))
elif test == 'testUpgradeInstanceWithOldDataFs': elif test == 'testUpgradeInstanceWithOldDataFs':
......
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