#!{{ bin_directory }}/runTestSuite_py """ Script to run NEO test suite using Nexedi's test node framework. """ import argparse, os, re, shutil, subprocess, sys, traceback from erp5.util import taskdistribution from time import gmtime, strftime # pattern to get test counts from stdout SUMMARY_RE = re.compile( r'^(.*)Summary (.*) (?P<test_count>\d+) (.*) (?P<unexpected_count>\d+|\.)' r' (.*) (?P<expected_count>\d+|\.) (.*) (?P<skip_count>\d+|\.)' r' (.*) (?P<duration>\d+(\.\d*)?|\.\d+)s', re.MULTILINE) # NEO specific environment TEMP_DIRECTORY = '{{directory.tmp}}/neo_tests' NEO_DB_SOCKET = '{{my_cnf_parameters.socket}}' RUN_NEO_TESTS_COMMAND = '{{ bin_directory }}/neotestrunner' def parseTestStdOut(data): """ Parse output of NEO testrunner script. """ test_count = 0 unexpected_count = 0 expected_count = 0 skip_count = 0 duration = 0 search = SUMMARY_RE.search(data) if search: groupdict = search.groupdict() test_count = int(groupdict['test_count']) duration = float(groupdict['duration']) try: # it can match '.'! skip_count = int(groupdict['skip_count']) except ValueError: pass try: # it can match '.'! unexpected_count = int(groupdict['unexpected_count']) except ValueError: pass try: # it can match '.'! expected_count = int(groupdict['expected_count']) except ValueError: pass return test_count, unexpected_count, expected_count, skip_count, duration def main(): parser = argparse.ArgumentParser(description='Run a test suite.') parser.add_argument('--test_suite', help='The test suite name') parser.add_argument('--test_suite_title', help='The test suite title') parser.add_argument('--test_node_title', help='The test node title') parser.add_argument('--project_title', help='The project title') parser.add_argument('--revision', help='The revision to test', default='dummy_revision') parser.add_argument('--node_quantity', help='ignored', type=int) parser.add_argument('--master_url', help='The Url of Master controling many suites') args = parser.parse_args() test_suite_title = args.test_suite_title or args.test_suite revision = args.revision test_name_list = 'SQLite', 'MySQL' tool = taskdistribution.TaskDistributionTool(portal_url = args.master_url) test_result = tool.createTestResult(revision = revision, test_name_list = test_name_list, node_title = args.test_node_title, test_title = test_suite_title, project_title = args.project_title) if test_result is None: return # run NEO tests while 1: test_result_line = test_result.start() if not test_result_line: break if os.path.exists(TEMP_DIRECTORY): shutil.rmtree(TEMP_DIRECTORY) os.mkdir(TEMP_DIRECTORY) args = [RUN_NEO_TESTS_COMMAND, '-ufz'] command = ' '.join(args) env = {'TEMP': TEMP_DIRECTORY, 'NEO_TESTS_ADAPTER': test_result_line.name, 'NEO_TEST_ZODB_FUNCTIONAL': '1', 'NEO_DB_USER': 'root', 'NEO_DB_SOCKET': NEO_DB_SOCKET} try: with open(os.devnull) as stdin: p = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) except Exception: # Catch any exception here, to warn user instead of being silent, # by generating fake error result result = dict(status_code=-1, command=command, stderr=traceback.format_exc(), stdout='') # XXX: inform test node master of error raise EnvironmentError(result) # parse test stdout / stderr, hint to speed up use files first! stdout, stderr = p.communicate() date = strftime("%Y/%m/%d %H:%M:%S", gmtime()) test_count, unexpected_count, expected_count, skip_count, duration = \ parseTestStdOut(stdout) # print to stdout so we can see in testnode logs sys.stdout.write(stdout) sys.stderr.write(stderr) # report status back to Nexedi ERP5 test_result_line.stop( test_count = test_count, error_count = unexpected_count, # XXX failure_count = expected_count, # XXX skip_count = skip_count, duration = duration, date = date, command = command, stdout= stdout, stderr= stderr, html_test_result='') if __name__ == "__main__": main()