Commit 0a09fe10 authored by Jérome Perrin's avatar Jérome Perrin

test: start test runner's zserver on partition IP and access it through an apache https proxy

Extend test runners to use partition IP  and run functional tests behind an https frontend.

See nexedi/slapos!374 for the slapos part and more detailed explanations.

/reviewed-on nexedi/erp5!729
parents 2a2ee5d3 31d4adde
...@@ -172,19 +172,30 @@ class FunctionalTestRunner: ...@@ -172,19 +172,30 @@ class FunctionalTestRunner:
return self.portal.portal_tests.TestTool_getResults(self.run_only) return self.portal.portal_tests.TestTool_getResults(self.run_only)
def _getTestURL(self): def _getTestURL(self):
return ZELENIUM_BASE_URL % (self.portal.portal_url(), self.run_only, # Access the https proxy in front of runUnitTest's zserver
self.user, self.password) base_url = os.getenv('zserver_frontend_url')
if base_url:
base_url = '%s%s' % (base_url, self.portal.getId())
else:
base_url = self.portal.portal_url()
return ZELENIUM_BASE_URL % (
base_url,
self.run_only,
self.user,
self.password)
def test(self, debug=0): def test(self, debug=0):
xvfb = Xvfb(self.instance_home) xvfb = Xvfb(self.instance_home)
try: try:
if not debug: if not (debug and os.getenv('DISPLAY')):
print("\nSet 'erp5_debug_mode' environment variable to 1" print("\nSet 'erp5_debug_mode' environment variable to 1"
" to use your existing display instead of Xvfb.") " to use your existing display instead of Xvfb.")
xvfb.run() xvfb.run()
capabilities = webdriver.common.desired_capabilities \ capabilities = webdriver.common.desired_capabilities \
.DesiredCapabilities.FIREFOX.copy() .DesiredCapabilities.FIREFOX.copy()
capabilities['marionette'] = True capabilities['marionette'] = True
# Zope is accessed through apache with a certificate not trusted by firefox
capabilities['acceptInsecureCerts'] = True
# Service workers are disabled on Firefox 52 ESR: # Service workers are disabled on Firefox 52 ESR:
# https://bugzilla.mozilla.org/show_bug.cgi?id=1338144 # https://bugzilla.mozilla.org/show_bug.cgi?id=1338144
options = webdriver.FirefoxOptions() options = webdriver.FirefoxOptions()
......
...@@ -24,6 +24,10 @@ class ERP5TypeTestSuite(TestSuite): ...@@ -24,6 +24,10 @@ class ERP5TypeTestSuite(TestSuite):
if self.__dict__.has_key("bt5_path"): if self.__dict__.has_key("bt5_path"):
args = ("--bt5_path=%s" % self.bt5_path,) + args args = ("--bt5_path=%s" % self.bt5_path,) + args
instance_number = self.instance or 1 instance_number = self.instance or 1
args = (
'--zserver=%s' % self.zserver_address_list[instance_number-1],
'--zserver_frontend_url=%s' % self.zserver_frontend_url_list[instance_number-1],
) + args
mysql_db_list = self.mysql_db_list[ mysql_db_list = self.mysql_db_list[
(instance_number-1) * self.mysql_db_count: (instance_number-1) * self.mysql_db_count:
(instance_number) * self.mysql_db_count] (instance_number) * self.mysql_db_count]
......
...@@ -154,7 +154,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase): ...@@ -154,7 +154,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
try: try:
_print(createZServer(log, zserver_type='webdav')) _print(createZServer(log, zserver_type='webdav'))
except RuntimeError, e: except RuntimeError, e:
ZopeTestCase._print(str(e)) ZopeTestCase._print('Could not start webdav zserver: %s\n' % e)
t = Thread(target=Lifetime.loop) t = Thread(target=Lifetime.loop)
t.setDaemon(1) t.setDaemon(1)
t.start() t.start()
......
#!/usr/bin/env python2.7 #!/usr/bin/env python2.7
import argparse, sys import argparse, sys, os, textwrap
from erp5.util import taskdistribution from erp5.util import taskdistribution
# XXX: This import is required, just to populate sys.modules['test_suite']. # XXX: This import is required, just to populate sys.modules['test_suite'].
...@@ -10,8 +10,14 @@ def _parsingErrorHandler(data, _): ...@@ -10,8 +10,14 @@ def _parsingErrorHandler(data, _):
print >> sys.stderr, 'Error parsing data:', repr(data) print >> sys.stderr, 'Error parsing data:', repr(data)
taskdistribution.patchRPCParser(_parsingErrorHandler) taskdistribution.patchRPCParser(_parsingErrorHandler)
def makeSuite(node_quantity=None, test_suite=None, revision=None, def makeSuite(
db_list=None, **kwargs): node_quantity=None,
test_suite=None,
revision=None,
db_list=None,
zserver_address_list=None,
zserver_frontend_url_list=None,
**kwargs):
# BBB tests (plural form) is only checked for backward compatibility # BBB tests (plural form) is only checked for backward compatibility
for k in sys.modules.keys(): for k in sys.modules.keys():
if k in ('tests', 'test',) or k.startswith('tests.') or k.startswith('test.'): if k in ('tests', 'test',) or k.startswith('tests.') or k.startswith('test.'):
...@@ -32,38 +38,71 @@ def makeSuite(node_quantity=None, test_suite=None, revision=None, ...@@ -32,38 +38,71 @@ def makeSuite(node_quantity=None, test_suite=None, revision=None,
suite = suite_class(revision=revision, suite = suite_class(revision=revision,
max_instance_count=node_quantity, max_instance_count=node_quantity,
mysql_db_list=db_list.split(','), mysql_db_list=db_list.split(','),
zserver_address_list=zserver_address_list.split(','),
zserver_frontend_url_list=zserver_frontend_url_list.split(','),
**kwargs) **kwargs)
return suite return suite
def main(): def main():
parser = argparse.ArgumentParser(description='Run a test suite.') parser = argparse.ArgumentParser(
parser.add_argument('--test_suite', help='The test suite name') description='Run a test suite.',
parser.add_argument('--test_suite_title', help='The test suite title', formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent('''
Tips:
Running a full test suite on a development machine can be achieved with:
%(prog)s --node_quantity=3 --test_suite=ERP5 --xvfb_bin=/path/to/Xvfb --firefox_bin=/path/to/firefox
'''))
# Parameters included in wrappers generated by SlapOS ERP5 software release.
# To handle backward compatibity, we prefer that the generated wrapper pass
# these parameters as environment variables. This way, if SlapOS SR is more
# recent, the parameter will be ignored by ERP5.
slapos_wrapper_group = parser.add_argument_group(
'SlapOS wrapper arguments',
description='Arguments passed automatically by SlapOS generated wrapper')
slapos_wrapper_group.add_argument('--db_list', help='A list of comma separated sql connection strings')
slapos_wrapper_group.add_argument('--conversion_server_url', default=None)
slapos_wrapper_group.add_argument('--conversion_server_retry_count', default=None)
slapos_wrapper_group.add_argument('--conversion_server_hostname', default=None)
slapos_wrapper_group.add_argument('--conversion_server_port', default=None)
slapos_wrapper_group.add_argument('--volatile_memcached_server_hostname', default=None)
slapos_wrapper_group.add_argument('--volatile_memcached_server_port', default=None)
slapos_wrapper_group.add_argument('--persistent_memcached_server_hostname', default=None)
slapos_wrapper_group.add_argument('--persistent_memcached_server_port', default=None)
slapos_wrapper_group.add_argument('--bt5_path', default=None)
slapos_wrapper_group.add_argument(
'--zserver_address_list',
help='A list of comma seperated host:port for ZServer.\n'
'Also taken from zserver_address_list environment variable.',
default=os.getenv('zserver_address_list'))
slapos_wrapper_group.add_argument(
'--zserver_frontend_url_list',
help='A list of comma seperated frontend URLs, one for each of zserver_address_list,'
'in the same order.\nAlso taken from zserver_frontend_url_list environment variable',
default=os.getenv('zserver_frontend_url_list'))
# Parameters passed by test node
testnode_group = parser.add_argument_group(
'test node arguments',
description='Arguments passed by testnode')
testnode_group.add_argument('--test_suite', help='The test suite name')
testnode_group.add_argument('--test_suite_title', help='The test suite title',
default=None) default=None)
parser.add_argument('--test_node_title', help='The test node title', testnode_group.add_argument('--test_node_title', help='The test node title',
default=None) default=None)
parser.add_argument('--project_title', help='The project title', testnode_group.add_argument('--project_title', help='The project title',
default=None) default=None)
parser.add_argument('--revision', help='The revision to test', testnode_group.add_argument('--revision', help='The revision to test',
default='dummy_revision') default='dummy_revision')
parser.add_argument('--node_quantity', help='Number of parallel tests to run', testnode_group.add_argument('--node_quantity', help='Number of parallel tests to run',
default=1, type=int) default=1, type=int)
parser.add_argument('--master_url', testnode_group.add_argument('--master_url',
help='The Url of Master controling many suites', help='The Url of Master controling many suites',
default=None) default=None)
parser.add_argument('--db_list', help='A list of sql connection strings') testnode_group.add_argument("--xvfb_bin", default=None)
# parameters that needs to be passed to runUnitTest testnode_group.add_argument("--firefox_bin", default=None)
parser.add_argument('--conversion_server_url', default=None)
parser.add_argument('--conversion_server_retry_count', default=None)
parser.add_argument('--conversion_server_hostname', default=None)
parser.add_argument('--conversion_server_port', default=None)
parser.add_argument('--volatile_memcached_server_hostname', default=None)
parser.add_argument('--volatile_memcached_server_port', default=None)
parser.add_argument('--persistent_memcached_server_hostname', default=None)
parser.add_argument('--persistent_memcached_server_port', default=None)
parser.add_argument('--bt5_path', default=None)
parser.add_argument("--xvfb_bin", default=None)
parser.add_argument("--firefox_bin", default=None)
args = parser.parse_args() args = parser.parse_args()
if args.bt5_path is not None: if args.bt5_path is not None:
...@@ -71,10 +110,21 @@ def main(): ...@@ -71,10 +110,21 @@ def main():
master = taskdistribution.TaskDistributor(args.master_url) master = taskdistribution.TaskDistributor(args.master_url)
test_suite_title = args.test_suite_title or args.test_suite test_suite_title = args.test_suite_title or args.test_suite
revision = args.revision revision = args.revision
if len(args.zserver_address_list.split(",")) < args.node_quantity:
print >> sys.stderr, 'Not enough zserver address/frontends for node quantity %s (%r)' % (
args.node_quantity, args.zserver_address_list)
sys.exit(1)
# sanity check
assert len(args.zserver_address_list.split(",")) == len(args.zserver_frontend_url_list.split(","))
suite = makeSuite(test_suite=args.test_suite, suite = makeSuite(test_suite=args.test_suite,
node_quantity=args.node_quantity, node_quantity=args.node_quantity,
revision=revision, revision=revision,
db_list=args.db_list, db_list=args.db_list,
zserver_address_list=args.zserver_address_list,
zserver_frontend_url_list=args.zserver_frontend_url_list,
bt5_path=args.bt5_path, bt5_path=args.bt5_path,
firefox_bin=args.firefox_bin, firefox_bin=args.firefox_bin,
xvfb_bin=args.xvfb_bin) xvfb_bin=args.xvfb_bin)
......
...@@ -141,10 +141,17 @@ Options: ...@@ -141,10 +141,17 @@ 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.
--zserver=[HOST:]PORT[,...] --zserver=ADDRESS[,...] Make ZServer listen on given IPv4 address.
Make ZServer listen on given host:port Adresses can be given in the following syntaxs:
- HOST:PORT
- PORT in this case, host will be 127.0.0.1
- HOST in this case a free port will be assigned
If used with --activity_node=, this can be a If used with --activity_node=, this can be a
comma-separated list of addresses. comma-separated list of addresses.
--zserver_frontend_url=STRING
URL of an http proxy where the zserver is reachable.
When running zelenium tests, the zserver will be
accessed from this URL.
--neo_storage Use a NEO storage (SQLite) instead of FileStorage. --neo_storage Use a NEO storage (SQLite) instead of FileStorage.
--products_path=path,path Comma-separated list of products paths locations --products_path=path,path Comma-separated list of products paths locations
which shall be used in test environment. which shall be used in test environment.
...@@ -727,6 +734,7 @@ def main(argument_list=None): ...@@ -727,6 +734,7 @@ def main(argument_list=None):
"zeo_client=", "zeo_client=",
"zeo_server=", "zeo_server=",
"zserver=", "zserver=",
"zserver_frontend_url=",
"neo_storage", "neo_storage",
"products_path=", "products_path=",
"sys_path=", "sys_path=",
...@@ -839,6 +847,8 @@ def main(argument_list=None): ...@@ -839,6 +847,8 @@ def main(argument_list=None):
os.environ["zeo_server"] = arg os.environ["zeo_server"] = arg
elif opt == "--zserver": elif opt == "--zserver":
os.environ["zserver"] = arg os.environ["zserver"] = arg
elif opt == "--zserver_frontend_url":
os.environ["zserver_frontend_url"] = arg
elif opt == "--neo_storage": elif opt == "--neo_storage":
os.environ["neo_storage"] = "" os.environ["neo_storage"] = ""
elif opt == "--products_path": elif opt == "--products_path":
......
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