# # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # """ Driver for running the tests on Windows. For a list of options, run this script with the --help option. """ # $HeadURL: https://svn.apache.org/repos/asf/subversion/branches/1.9.x/win-tests.py $ # $LastChangedRevision: 1718291 $ import os, sys, subprocess import filecmp import shutil import traceback import logging try: # Python >=3.0 import configparser except ImportError: # Python <3.0 import ConfigParser as configparser import string import random import getopt try: my_getopt = getopt.gnu_getopt except AttributeError: my_getopt = getopt.getopt def _usage_exit(): "print usage, exit the script" print("Driver for running the tests on Windows.") print("Usage: python win-tests.py [option] [test-path]") print("") print("Valid options:") print(" -r, --release : test the Release configuration") print(" -d, --debug : test the Debug configuration (default)") print(" --bin=PATH : use the svn binaries installed in PATH") print(" -u URL, --url=URL : run ra_dav or ra_svn tests against URL;") print(" will start svnserve for ra_svn tests") print(" -v, --verbose : talk more") print(" -f, --fs-type=type : filesystem type to use (fsfs is default)") print(" -c, --cleanup : cleanup after running a test") print(" -t, --test=TEST : Run the TEST test (all is default); use") print(" TEST#n to run a particular test number,") print(" multiples also accepted e.g. '2,4-7'") print(" --log-level=LEVEL : Set log level to LEVEL (E.g. DEBUG)") print(" --log-to-stdout : Write log results to stdout") print(" --svnserve-args=list : comma-separated list of arguments for") print(" svnserve") print(" default is '-d,-r,'") print(" --asp.net-hack : use '_svn' instead of '.svn' for the admin") print(" dir name") print(" --httpd-dir : location where Apache HTTPD is installed") print(" --httpd-port : port for Apache HTTPD; random port number") print(" will be used, if not specified") print(" --httpd-daemon : Run Apache httpd as daemon") print(" --httpd-service : Run Apache httpd as Windows service (default)") print(" --httpd-no-log : Disable httpd logging") print(" --http-short-circuit : Use SVNPathAuthz short_circuit on HTTP server") print(" --disable-http-v2 : Do not advertise support for HTTPv2 on server") print(" --disable-bulk-updates : Disable bulk updates on HTTP server") print(" --ssl-cert : Path to SSL server certificate to trust.") print(" --javahl : Run the javahl tests instead of the normal tests") print(" --swig=language : Run the swig perl/python/ruby tests instead of") print(" the normal tests") print(" --list : print test doc strings only") print(" --milestone-filter=RE : RE is a regular expression pattern that (when") print(" used with --list) limits the tests listed to") print(" those with an associated issue in the tracker") print(" which has a target milestone that matches RE.") print(" --mode-filter=TYPE : limit tests to expected TYPE = XFAIL, SKIP, PASS,") print(" or 'ALL' (default)") print(" --enable-sasl : enable Cyrus SASL authentication for") print(" svnserve") print(" -p, --parallel : run multiple tests in parallel") print(" --server-minor-version : the minor version of the server being") print(" tested") print(" --config-file : Configuration file for tests") print(" --fsfs-sharding : Specify shard size (for fsfs)") print(" --fsfs-packing : Run 'svnadmin pack' automatically") print(" -q, --quiet : Deprecated; this is the default.") print(" Use --set-log-level instead.") sys.exit(0) CMDLINE_TEST_SCRIPT_PATH = 'subversion/tests/cmdline/' CMDLINE_TEST_SCRIPT_NATIVE_PATH = CMDLINE_TEST_SCRIPT_PATH.replace('/', os.sep) sys.path.insert(0, os.path.join('build', 'generator')) sys.path.insert(1, 'build') import gen_win_dependencies import gen_base version_header = os.path.join('subversion', 'include', 'svn_version.h') cp = configparser.ConfigParser() cp.read('gen-make.opts') gen_obj = gen_win_dependencies.GenDependenciesBase('build.conf', version_header, cp.items('options')) opts, args = my_getopt(sys.argv[1:], 'hrdvqct:pu:f:', ['release', 'debug', 'verbose', 'quiet', 'cleanup', 'test=', 'url=', 'svnserve-args=', 'fs-type=', 'asp.net-hack', 'httpd-dir=', 'httpd-port=', 'httpd-daemon', 'httpd-server', 'http-short-circuit', 'httpd-no-log', 'disable-http-v2', 'disable-bulk-updates', 'help', 'fsfs-packing', 'fsfs-sharding=', 'javahl', 'swig=', 'list', 'enable-sasl', 'bin=', 'parallel', 'config-file=', 'server-minor-version=', 'log-level=', 'log-to-stdout', 'mode-filter=', 'milestone-filter=', 'ssl-cert=']) if len(args) > 1: print('Warning: non-option arguments after the first one will be ignored') # Interpret the options and set parameters base_url, fs_type, verbose, cleanup = None, None, None, None repo_loc = 'local repository.' objdir = 'Debug' log = 'tests.log' faillog = 'fails.log' run_svnserve = None svnserve_args = None run_httpd = None httpd_port = None httpd_service = None httpd_no_log = None http_short_circuit = False advertise_httpv2 = True http_bulk_updates = True list_tests = None milestone_filter = None test_javahl = None test_swig = None enable_sasl = None svn_bin = None parallel = None fsfs_sharding = None fsfs_packing = None server_minor_version = None config_file = None log_to_stdout = None mode_filter=None tests_to_run = [] log_level = None ssl_cert = None for opt, val in opts: if opt in ('-h', '--help'): _usage_exit() elif opt in ('-u', '--url'): base_url = val elif opt in ('-f', '--fs-type'): fs_type = val elif opt in ('-v', '--verbose'): verbose = 1 log_level = logging.DEBUG elif opt in ('-c', '--cleanup'): cleanup = 1 elif opt in ('-t', '--test'): tests_to_run.append(val) elif opt in ['-r', '--release']: objdir = 'Release' elif opt in ['-d', '--debug']: objdir = 'Debug' elif opt == '--svnserve-args': svnserve_args = val.split(',') run_svnserve = 1 elif opt == '--asp.net-hack': os.environ['SVN_ASP_DOT_NET_HACK'] = opt elif opt == '--httpd-dir': abs_httpd_dir = os.path.abspath(val) run_httpd = 1 elif opt == '--httpd-port': httpd_port = int(val) elif opt == '--httpd-daemon': httpd_service = 0 elif opt == '--httpd-service': httpd_service = 1 elif opt == '--httpd-no-log': httpd_no_log = 1 elif opt == '--http-short-circuit': http_short_circuit = True elif opt == '--disable-http-v2': advertise_httpv2 = False elif opt == '--disable-bulk-updates': http_bulk_updates = False elif opt == '--fsfs-sharding': fsfs_sharding = int(val) elif opt == '--fsfs-packing': fsfs_packing = 1 elif opt == '--javahl': test_javahl = 1 elif opt == '--swig': if val not in ['perl', 'python', 'ruby']: sys.stderr.write('Running \'%s\' swig tests not supported (yet).\n' % (val,)) test_swig = val elif opt == '--list': list_tests = 1 elif opt == '--milestone-filter': milestone_filter = val elif opt == '--mode-filter': mode_filter = val elif opt == '--enable-sasl': enable_sasl = 1 base_url = "svn://localhost/" elif opt == '--server-minor-version': server_minor_version = int(val) elif opt == '--bin': svn_bin = val elif opt in ('-p', '--parallel'): parallel = 1 elif opt in ('--config-file'): config_file = val elif opt == '--log-to-stdout': log_to_stdout = 1 elif opt == '--log-level': log_level = getattr(logging, val, None) or int(val) elif opt == '--ssl-cert': ssl_cert = val # Calculate the source and test directory names abs_srcdir = os.path.abspath("") abs_objdir = os.path.join(abs_srcdir, objdir) if len(args) == 0: abs_builddir = abs_objdir create_dirs = 0 else: abs_builddir = os.path.abspath(args[0]) create_dirs = 1 # Default to fsfs explicitly if not fs_type: fs_type = 'fsfs' if fs_type == 'bdb': all_tests = gen_obj.test_progs + gen_obj.bdb_test_progs \ + gen_obj.scripts + gen_obj.bdb_scripts else: all_tests = gen_obj.test_progs + gen_obj.scripts client_tests = [x for x in all_tests if x.startswith(CMDLINE_TEST_SCRIPT_PATH)] if run_httpd: if not httpd_port: httpd_port = random.randrange(1024, 30000) if not base_url: base_url = 'http://localhost:' + str(httpd_port) if base_url: repo_loc = 'remote repository ' + base_url + '.' if base_url[:4] == 'http': log = 'dav-tests.log' faillog = 'dav-fails.log' elif base_url[:3] == 'svn': log = 'svn-tests.log' faillog = 'svn-fails.log' run_svnserve = 1 else: # Don't know this scheme, but who're we to judge whether it's # correct or not? log = 'url-tests.log' faillog = 'url-fails.log' # Have to move the executables where the tests expect them to be copied_execs = [] # Store copied exec files to avoid the final dir scan def create_target_dir(dirname): tgt_dir = os.path.join(abs_builddir, dirname) if not os.path.exists(tgt_dir): if verbose: print("mkdir: %s" % tgt_dir) os.makedirs(tgt_dir) def copy_changed_file(src, tgt=None, to_dir=None, cleanup=True): if not os.path.isfile(src): print('Could not find ' + src) sys.exit(1) if to_dir and not tgt: tgt = os.path.join(to_dir, os.path.basename(src)) elif not tgt or (tgt and to_dir): raise RuntimeError("Using 'tgt' *or* 'to_dir' is required" % (tgt,)) elif tgt and os.path.isdir(tgt): raise RuntimeError("'%s' is a directory. Use to_dir=" % (tgt,)) if os.path.exists(tgt): assert os.path.isfile(tgt) if filecmp.cmp(src, tgt): if verbose: print("same: %s" % src) print(" and: %s" % tgt) return 0 if verbose: print("copy: %s" % src) print(" to: %s" % tgt) shutil.copy(src, tgt) if cleanup: copied_execs.append(tgt) def locate_libs(): "Move DLLs to a known location and set env vars" debug = (objdir == 'Debug') for lib in gen_obj._libraries.values(): if debug: name, dir = lib.debug_dll_name, lib.debug_dll_dir else: name, dir = lib.dll_name, lib.dll_dir if name and dir: src = os.path.join(dir, name) if os.path.exists(src): copy_changed_file(src, to_dir=abs_builddir, cleanup=False) for name in lib.extra_bin: src = os.path.join(dir, name) copy_changed_file(src, to_dir=abs_builddir) # Copy the Subversion library DLLs for i in gen_obj.graph.get_all_sources(gen_base.DT_INSTALL): if isinstance(i, gen_base.TargetLib) and i.msvc_export: src = os.path.join(abs_objdir, i.filename) if os.path.isfile(src): copy_changed_file(src, to_dir=abs_builddir, cleanup=False) # Copy the Apache modules if run_httpd and cp.has_option('options', '--with-httpd'): mod_dav_svn_path = os.path.join(abs_objdir, 'subversion', 'mod_dav_svn', 'mod_dav_svn.so') mod_authz_svn_path = os.path.join(abs_objdir, 'subversion', 'mod_authz_svn', 'mod_authz_svn.so') mod_dontdothat_path = os.path.join(abs_objdir, 'tools', 'server-side', 'mod_dontdothat', 'mod_dontdothat.so') copy_changed_file(mod_dav_svn_path, to_dir=abs_builddir, cleanup=False) copy_changed_file(mod_authz_svn_path, to_dir=abs_builddir, cleanup=False) copy_changed_file(mod_dontdothat_path, to_dir=abs_builddir, cleanup=False) os.environ['PATH'] = abs_builddir + os.pathsep + os.environ['PATH'] def fix_case(path): path = os.path.normpath(path) parts = path.split(os.path.sep) drive = parts[0].upper() parts = parts[1:] path = drive + os.path.sep for part in parts: dirs = os.listdir(path) for dir in dirs: if dir.lower() == part.lower(): path = os.path.join(path, dir) break return path class Svnserve: "Run svnserve for ra_svn tests" def __init__(self, svnserve_args, objdir, abs_objdir, abs_builddir): self.args = svnserve_args self.name = 'svnserve.exe' self.kind = objdir self.path = os.path.join(abs_objdir, 'subversion', 'svnserve', self.name) self.root = os.path.join(abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH) self.proc = None def __del__(self): "Stop svnserve when the object is deleted" self.stop() def _quote(self, arg): if ' ' in arg: return '"' + arg + '"' else: return arg def start(self): if not self.args: args = [self.name, '-d', '-r', self.root] else: args = [self.name] + self.args print('Starting %s %s' % (self.kind, self.name)) self.proc = subprocess.Popen([self.path] + args[1:]) def stop(self): if self.proc is not None: try: print('Stopping %s' % self.name) self.proc.poll(); if self.proc.returncode is None: self.proc.kill(); return except AttributeError: pass print('Svnserve.stop not implemented') class Httpd: "Run httpd for DAV tests" def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port, service, no_log, httpv2, short_circuit, bulk_updates): self.name = 'apache.exe' self.httpd_port = httpd_port self.httpd_dir = abs_httpd_dir if httpv2: self.httpv2_option = 'on' else: self.httpv2_option = 'off' if bulk_updates: self.bulkupdates_option = 'on' else: self.bulkupdates_option = 'off' self.service = service self.proc = None self.path = os.path.join(self.httpd_dir, 'bin', self.name) if short_circuit: self.path_authz_option = 'short_circuit' else: self.path_authz_option = 'on' if not os.path.exists(self.path): self.name = 'httpd.exe' self.path = os.path.join(self.httpd_dir, 'bin', self.name) if not os.path.exists(self.path): raise RuntimeError("Could not find a valid httpd binary!") self.root_dir = os.path.join(CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'httpd') self.root = os.path.join(abs_builddir, self.root_dir) self.authz_file = os.path.join(abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'svn-test-work', 'authz') self.dontdothat_file = os.path.join(abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'svn-test-work', 'dontdothat') self.httpd_config = os.path.join(self.root, 'httpd.conf') self.httpd_users = os.path.join(self.root, 'users') self.httpd_mime_types = os.path.join(self.root, 'mime.types') self.httpd_groups = os.path.join(self.root, 'groups') self.abs_builddir = abs_builddir self.abs_objdir = abs_objdir self.service_name = 'svn-test-httpd-' + str(httpd_port) if self.service: self.httpd_args = [self.name, '-n', self._quote(self.service_name), '-f', self._quote(self.httpd_config)] else: self.httpd_args = [self.name, '-f', self._quote(self.httpd_config)] create_target_dir(self.root_dir) self._create_users_file() self._create_groups_file() self._create_mime_types_file() self._create_dontdothat_file() # Obtain version. version_vals = gen_obj._libraries['httpd'].version.split('.') self.httpd_ver = float('%s.%s' % (version_vals[0], version_vals[1])) # Create httpd config file fp = open(self.httpd_config, 'w') # Limit the number of threads (default = 64) fp.write('\n') fp.write('ThreadsPerChild 16\n') fp.write('\n') # Global Environment fp.write('ServerRoot ' + self._quote(self.root) + '\n') fp.write('DocumentRoot ' + self._quote(self.root) + '\n') fp.write('ServerName localhost\n') fp.write('PidFile pid\n') fp.write('ErrorLog log\n') fp.write('Listen ' + str(self.httpd_port) + '\n') if not no_log: fp.write('LogFormat "%h %l %u %t \\"%r\\" %>s %b" common\n') fp.write('Customlog log common\n') fp.write('LogLevel Debug\n') else: fp.write('LogLevel Crit\n') # Write LoadModule for minimal system module fp.write(self._sys_module('dav_module', 'mod_dav.so')) if self.httpd_ver >= 2.3: fp.write(self._sys_module('access_compat_module', 'mod_access_compat.so')) fp.write(self._sys_module('authz_core_module', 'mod_authz_core.so')) fp.write(self._sys_module('authz_user_module', 'mod_authz_user.so')) fp.write(self._sys_module('authn_core_module', 'mod_authn_core.so')) if self.httpd_ver >= 2.2: fp.write(self._sys_module('auth_basic_module', 'mod_auth_basic.so')) fp.write(self._sys_module('authn_file_module', 'mod_authn_file.so')) fp.write(self._sys_module('authz_groupfile_module', 'mod_authz_groupfile.so')) fp.write(self._sys_module('authz_host_module', 'mod_authz_host.so')) else: fp.write(self._sys_module('auth_module', 'mod_auth.so')) fp.write(self._sys_module('alias_module', 'mod_alias.so')) fp.write(self._sys_module('mime_module', 'mod_mime.so')) fp.write(self._sys_module('log_config_module', 'mod_log_config.so')) # Write LoadModule for Subversion modules fp.write(self._svn_module('dav_svn_module', 'mod_dav_svn.so')) fp.write(self._svn_module('authz_svn_module', 'mod_authz_svn.so')) # And for mod_dontdothat fp.write(self._svn_module('dontdothat_module', 'mod_dontdothat.so')) # Don't handle .htaccess, symlinks, etc. fp.write('\n') fp.write('AllowOverride None\n') fp.write('Options None\n') fp.write('\n\n') # Define two locations for repositories fp.write(self._svn_repo('repositories')) fp.write(self._svn_repo('local_tmp')) fp.write(self._svn_authz_repo()) # And two redirects for the redirect tests fp.write('RedirectMatch permanent ^/svn-test-work/repositories/' 'REDIRECT-PERM-(.*)$ /svn-test-work/repositories/$1\n') fp.write('RedirectMatch ^/svn-test-work/repositories/' 'REDIRECT-TEMP-(.*)$ /svn-test-work/repositories/$1\n') fp.write('TypesConfig ' + self._quote(self.httpd_mime_types) + '\n') fp.write('HostNameLookups Off\n') fp.close() def __del__(self): "Stop httpd when the object is deleted" self.stop() def _quote(self, arg): if ' ' in arg: return '"' + arg + '"' else: return arg def _create_users_file(self): "Create users file" htpasswd = os.path.join(self.httpd_dir, 'bin', 'htpasswd.exe') # Create the cheapest to compare password form for our testsuite os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bcp', self.httpd_users, 'jrandom', 'rayjandom']) os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users, 'jconstant', 'rayjandom']) os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users, 'JRANDOM', 'rayjandom']) os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users, 'JCONSTANT', 'rayjandom']) def _create_groups_file(self): "Create groups for mod_authz_svn tests" fp = open(self.httpd_groups, 'w') fp.write('random: jrandom\n') fp.write('constant: jconstant\n') fp.close() def _create_mime_types_file(self): "Create empty mime.types file" fp = open(self.httpd_mime_types, 'w') fp.close() def _create_dontdothat_file(self): "Create empty mime.types file" # If the tests have not previously been run or were cleaned # up, then 'svn-test-work' does not exist yet. parent_dir = os.path.dirname(self.dontdothat_file) if not os.path.exists(parent_dir): os.makedirs(parent_dir) fp = open(self.dontdothat_file, 'w') fp.write('[recursive-actions]\n') fp.write('/ = deny\n') fp.close() def _sys_module(self, name, path): full_path = os.path.join(self.httpd_dir, 'modules', path) return 'LoadModule ' + name + " " + self._quote(full_path) + '\n' def _svn_module(self, name, path): full_path = os.path.join(self.abs_builddir, path) return 'LoadModule ' + name + ' ' + self._quote(full_path) + '\n' def _svn_repo(self, name): path = os.path.join(self.abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'svn-test-work', name) location = '/svn-test-work/' + name ddt_location = '/ddt-test-work/' + name return \ '\n' \ ' DAV svn\n' \ ' SVNParentPath ' + self._quote(path) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ ' SVNAllowBulkUpdates ' + self.bulkupdates_option + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' AuthType Basic\n' \ ' AuthName "Subversion Repository"\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user\n' \ '\n' \ '\n' \ ' DAV svn\n' \ ' SVNParentPath ' + self._quote(path) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ ' SVNAllowBulkUpdates ' + self.bulkupdates_option + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' AuthType Basic\n' \ ' AuthName "Subversion Repository"\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user\n' \ ' DontDoThatConfigFile ' + self._quote(self.dontdothat_file) + '\n' \ '\n' def _svn_authz_repo(self): local_tmp = os.path.join(self.abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'svn-test-work', 'local_tmp') return \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' ' + '\n' \ ' Require all granted' + '\n' \ ' ' + '\n' \ ' ' + '\n' \ ' Allow from all' + '\n' \ ' ' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' Satisfy Any' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' AuthzSVNNoAuthWhenAnonymousAllowed On' + '\n' \ ' SVNPathAuthz On' + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' AuthzSVNAnonymous Off' + '\n' \ ' SVNPathAuthz On' + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' AuthzForceUsernameCase Lower' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' Require valid-user' + '\n' \ ' AuthzForceUsernameCase Lower' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' AuthGroupFile ' + self._quote(self.httpd_groups) + '\n' \ ' Require group random' + '\n' \ ' AuthzSVNAuthoritative Off' + '\n' \ ' SVNPathAuthz On' + '\n' \ '' + '\n' \ '' + '\n' \ '' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' AuthzSendForbiddenOnFailure On' + '\n' \ ' Satisfy All' + '\n' \ ' ' + '\n' \ ' Require valid-user' + '\n' \ ' Require expr req(\'ALLOW\') == \'1\'' + '\n' \ ' ' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ ''+ '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ ' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \ ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ ' SVNListParentPath On' + '\n' \ ' AuthType Basic' + '\n' \ ' AuthName "Subversion Repository"' + '\n' \ ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ ' AuthzSendForbiddenOnFailure On' + '\n' \ ' Satisfy All' + '\n' \ ' ' + '\n' \ ' Require valid-user' + '\n' \ ' Require expr req(\'ALLOW\') == \'1\'' + '\n' \ '' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '' + '\n' \ '' + '\n' \ def start(self): if self.service: self._start_service() else: self._start_daemon() def stop(self): if self.service: self._stop_service() else: self._stop_daemon() def _start_service(self): "Install and start HTTPD service" print('Installing service %s' % self.service_name) os.spawnv(os.P_WAIT, self.path, self.httpd_args + ['-k', 'install']) print('Starting service %s' % self.service_name) os.spawnv(os.P_WAIT, self.path, self.httpd_args + ['-k', 'start']) def _stop_service(self): "Stop and uninstall HTTPD service" os.spawnv(os.P_WAIT, self.path, self.httpd_args + ['-k', 'stop']) os.spawnv(os.P_WAIT, self.path, self.httpd_args + ['-k', 'uninstall']) def _start_daemon(self): "Start HTTPD as daemon" print('Starting httpd as daemon') print(self.httpd_args) self.proc = subprocess.Popen([self.path] + self.httpd_args[1:]) def _stop_daemon(self): "Stop the HTTPD daemon" if self.proc is not None: try: print('Stopping %s' % self.name) self.proc.poll(); if self.proc.returncode is None: self.proc.kill(); return except AttributeError: pass print('Httpd.stop_daemon not implemented') # Move the binaries to the test directory create_target_dir(abs_builddir) locate_libs() if create_dirs: for i in gen_obj.graph.get_all_sources(gen_base.DT_INSTALL): if isinstance(i, gen_base.TargetExe): src = os.path.join(abs_objdir, i.filename) if os.path.isfile(src): dst = os.path.join(abs_builddir, i.filename) create_target_dir(os.path.dirname(dst)) copy_changed_file(src, dst) # Create the base directory for Python tests create_target_dir(CMDLINE_TEST_SCRIPT_NATIVE_PATH) # Ensure the tests directory is correctly cased abs_builddir = fix_case(abs_builddir) daemon = None # Run the tests # No need to start any servers if we are only listing the tests. if not list_tests: if run_svnserve: daemon = Svnserve(svnserve_args, objdir, abs_objdir, abs_builddir) if run_httpd: daemon = Httpd(abs_httpd_dir, abs_objdir, abs_builddir, httpd_port, httpd_service, httpd_no_log, advertise_httpv2, http_short_circuit, http_bulk_updates) # Start service daemon, if any if daemon: daemon.start() # Find the full path and filename of any test that is specified just by # its base name. if len(tests_to_run) != 0: tests = [] for t in tests_to_run: tns = None if '#' in t: t, tns = t.split('#') test = [x for x in all_tests if x.split('/')[-1] == t] if not test and not (t.endswith('-test.exe') or t.endswith('_tests.py')): # The lengths of '-test.exe' and of '_tests.py' are both 9. test = [x for x in all_tests if x.split('/')[-1][:-9] == t] if not test: print("Skipping test '%s', test not found." % t) elif tns: tests.append('%s#%s' % (test[0], tns)) else: tests.extend(test) tests_to_run = tests else: tests_to_run = all_tests if list_tests: print('Listing %s configuration on %s' % (objdir, repo_loc)) else: print('Testing %s configuration on %s' % (objdir, repo_loc)) sys.path.insert(0, os.path.join(abs_srcdir, 'build')) if not test_javahl and not test_swig: import run_tests if log_to_stdout: log_file = None fail_log_file = None else: log_file = os.path.join(abs_builddir, log) fail_log_file = os.path.join(abs_builddir, faillog) if run_httpd: httpd_version = gen_obj._libraries['httpd'].version else: httpd_version = None opts, args = run_tests.create_parser().parse_args([]) opts.url = base_url opts.fs_type = fs_type opts.http_library = 'serf' opts.server_minor_version = server_minor_version opts.cleanup = cleanup opts.enable_sasl = enable_sasl opts.parallel = parallel opts.config_file = config_file opts.fsfs_sharding = fsfs_sharding opts.fsfs_packing = fsfs_packing opts.list_tests = list_tests opts.svn_bin = svn_bin opts.mode_filter = mode_filter opts.milestone_filter = milestone_filter opts.httpd_version = httpd_version opts.set_log_level = log_level opts.ssl_cert = ssl_cert th = run_tests.TestHarness(abs_srcdir, abs_builddir, log_file, fail_log_file, opts) old_cwd = os.getcwd() try: os.chdir(abs_builddir) failed = th.run(tests_to_run) except: os.chdir(old_cwd) raise else: os.chdir(old_cwd) elif test_javahl: failed = False java_exe = None for path in os.environ["PATH"].split(os.pathsep): if os.path.isfile(os.path.join(path, 'java.exe')): java_exe = os.path.join(path, 'java.exe') break if not java_exe and 'java_sdk' in gen_obj._libraries: jdk = gen_obj._libraries['java_sdk'] if os.path.isfile(os.path.join(jdk.lib_dir, '../bin/java.exe')): java_exe = os.path.join(jdk.lib_dir, '../bin/java.exe') if not java_exe: print('Java not found. Skipping Java tests') else: args = (os.path.abspath(java_exe),) if (objdir == 'Debug'): args = args + ('-Xcheck:jni',) args = args + ( '-Dtest.rootdir=' + os.path.join(abs_builddir, 'javahl'), '-Dtest.srcdir=' + os.path.join(abs_srcdir, 'subversion/bindings/javahl'), '-Dtest.rooturl=', '-Dtest.fstype=' + fs_type , '-Dtest.tests=', '-Djava.library.path=' + os.path.join(abs_objdir, 'subversion/bindings/javahl/native'), '-classpath', os.path.join(abs_srcdir, 'subversion/bindings/javahl/classes') +';' + gen_obj.junit_path ) sys.stderr.flush() print('Running org.apache.subversion tests:') sys.stdout.flush() r = subprocess.call(args + tuple(['org.apache.subversion.javahl.RunTests'])) sys.stdout.flush() sys.stderr.flush() if (r != 0): print('[Test runner reported failure]') failed = True print('Running org.tigris.subversion tests:') sys.stdout.flush() r = subprocess.call(args + tuple(['org.tigris.subversion.javahl.RunTests'])) sys.stdout.flush() sys.stderr.flush() if (r != 0): print('[Test runner reported failure]') failed = True elif test_swig == 'perl': failed = False swig_dir = os.path.join(abs_builddir, 'swig') swig_pl_dir = os.path.join(swig_dir, 'p5lib') swig_pl_svn = os.path.join(swig_pl_dir, 'SVN') swig_pl_auto_svn = os.path.join(swig_pl_dir, 'auto', 'SVN') create_target_dir(swig_pl_svn) for i in gen_obj.graph.get_all_sources(gen_base.DT_INSTALL): if isinstance(i, gen_base.TargetSWIG) and i.lang == 'perl': mod_dir = os.path.join(swig_pl_auto_svn, '_' + i.name[5:].capitalize()) create_target_dir(mod_dir) copy_changed_file(os.path.join(abs_objdir, i.filename), to_dir=mod_dir) elif isinstance(i, gen_base.TargetSWIGLib) and i.lang == 'perl': copy_changed_file(os.path.join(abs_objdir, i.filename), to_dir=abs_builddir) pm_src = os.path.join(abs_srcdir, 'subversion', 'bindings', 'swig', 'perl', 'native') tests = [] for root, dirs, files in os.walk(pm_src): for name in files: if name.endswith('.pm'): fn = os.path.join(root, name) copy_changed_file(fn, to_dir=swig_pl_svn) elif name.endswith('.t'): tests.append(os.path.relpath(os.path.join(root, name), pm_src)) perl5lib = swig_pl_dir if 'PERL5LIB' in os.environ: perl5lib += os.pathsep + os.environ['PERL5LIB'] perl_exe = 'perl.exe' print('-- Running Swig Perl tests --') sys.stdout.flush() old_cwd = os.getcwd() try: os.chdir(pm_src) os.environ['PERL5LIB'] = perl5lib os.environ["SVN_DBG_NO_ABORT_ON_ERROR_LEAK"] = 'YES' r = subprocess.call([ perl_exe, '-MExtUtils::Command::MM', '-e', 'test_harness()' ] + tests) finally: os.chdir(old_cwd) if (r != 0): print('[Test runner reported failure]') failed = True elif test_swig == 'python': failed = False swig_dir = os.path.join(abs_builddir, 'swig') swig_py_dir = os.path.join(swig_dir, 'pylib') swig_py_libsvn = os.path.join(swig_py_dir, 'libsvn') swig_py_svn = os.path.join(swig_py_dir, 'svn') create_target_dir(swig_py_libsvn) create_target_dir(swig_py_svn) for i in gen_obj.graph.get_all_sources(gen_base.DT_INSTALL): if (isinstance(i, gen_base.TargetSWIG) or isinstance(i, gen_base.TargetSWIGLib)) and i.lang == 'python': src = os.path.join(abs_objdir, i.filename) copy_changed_file(src, to_dir=swig_py_libsvn) py_src = os.path.join(abs_srcdir, 'subversion', 'bindings', 'swig', 'python') for py_file in os.listdir(py_src): if py_file.endswith('.py'): copy_changed_file(os.path.join(py_src, py_file), to_dir=swig_py_libsvn) py_src_svn = os.path.join(py_src, 'svn') for py_file in os.listdir(py_src_svn): if py_file.endswith('.py'): copy_changed_file(os.path.join(py_src_svn, py_file), to_dir=swig_py_svn) print('-- Running Swig Python tests --') sys.stdout.flush() pythonpath = swig_py_dir if 'PYTHONPATH' in os.environ: pythonpath += os.pathsep + os.environ['PYTHONPATH'] python_exe = 'python.exe' old_cwd = os.getcwd() try: os.environ['PYTHONPATH'] = pythonpath r = subprocess.call([ python_exe, os.path.join(py_src, 'tests', 'run_all.py') ]) finally: os.chdir(old_cwd) if (r != 0): print('[Test runner reported failure]') failed = True elif test_swig == 'ruby': failed = False if 'ruby' not in gen_obj._libraries: print('Ruby not found. Skipping Ruby tests') else: ruby_lib = gen_obj._libraries['ruby'] ruby_exe = 'ruby.exe' ruby_subdir = os.path.join('subversion', 'bindings', 'swig', 'ruby') ruby_args = [ '-I', os.path.join(abs_srcdir, ruby_subdir), os.path.join(abs_srcdir, ruby_subdir, 'test', 'run-test.rb'), '--verbose' ] print('-- Running Swig Ruby tests --') sys.stdout.flush() old_cwd = os.getcwd() try: os.chdir(ruby_subdir) os.environ["BUILD_TYPE"] = objdir os.environ["SVN_DBG_NO_ABORT_ON_ERROR_LEAK"] = 'YES' r = subprocess.call([ruby_exe] + ruby_args) finally: os.chdir(old_cwd) sys.stdout.flush() sys.stderr.flush() if (r != 0): print('[Test runner reported failure]') failed = True # Stop service daemon, if any if daemon: del daemon # Remove the execs again for tgt in copied_execs: try: if os.path.isfile(tgt): if verbose: print("kill: %s" % tgt) os.unlink(tgt) except: traceback.print_exc(file=sys.stdout) pass if failed: sys.exit(1)