[[[ In cmdline tests, use subprocess.Popen for executing commands to allow support for exit-code checks on both Windows and posix systems. This makes the test suite require Python version >= 2.4. * subversion/tests/cmdline/svntest/main.py (global): Import subprocess instead of popen2. Remove variable "platform_with_popen3_class". (open_pipe): Remove "binary_mode" parameter. Use subprocess.Popen for spawning the child process. (wait_on_pipe): Interpret the return value of wait() according to subprocess.Popen semantics. (run_command, run_command_stdin, spawn_process): Remove "binary_mode" parameter, and do not pass that parameter to run_command_stdin, open_pipe. (run_svn, run_svnadmin, run_svnlook, run_svnsync, run_svnversion, create_repos, copy_repos, TestSpawningThread.run_one): Do not pass "binary_mode" parameter to run_command, open_pipe, or spawn_process. * subversion/tests/cmdline/svntest/actions.py (run_and_verify_svnlook, run_and_verify_svnlook2, run_and_verify_svnadmin, run_and_verify_svnadmin2, run_and_verify_svnversion, run_and_verify_svnversion2, run_and_verify_svn, run_and_verify_svn2, run_and_verify_svn_match_any, run_and_verify_svn_match_any2): Remove the caveat comment stating that exit-code checks are skipped for some platforms. (run_and_verify_load, check_prop): Do not pass the "binary_mode" parameter to run_command_stdin or run_command. * subversion/tests/cmdline/svnadmin_tests.py, subversion/tests/cmdline/svnlook_tests.py, subversion/tests/cmdline/svndumpfilter_tests.py, subversion/tests/cmdline/getopt_tests.py: Do not pass the "binary_mode" parameter to run_command or run_command_stdin. Suggested by: brane Patch by: Jeremy Hinds ]]] Index: subversion/tests/cmdline/svnadmin_tests.py =================================================================== --- subversion/tests/cmdline/svnadmin_tests.py (revision 30372) +++ subversion/tests/cmdline/svnadmin_tests.py (working copy) @@ -90,7 +90,7 @@ dump = [ dump ] exit_code, output, errput = svntest.main.run_command_stdin( - svntest.main.svnadmin_binary, expected_stderr, 1, dump, + svntest.main.svnadmin_binary, expected_stderr, dump, 'load', '--quiet', sbox.repo_dir, *varargs) if expected_stdout: Index: subversion/tests/cmdline/svnlook_tests.py =================================================================== --- subversion/tests/cmdline/svnlook_tests.py (revision 30372) +++ subversion/tests/cmdline/svnlook_tests.py (working copy) @@ -37,7 +37,7 @@ """Run svnlook with VARARGS, returns stdout as list of lines. Raises Failure if any stderr messages.""" exit_code, output, dummy_errput = svntest.main.run_command( - svntest.main.svnlook_binary, 0, 0, *varargs) + svntest.main.svnlook_binary, 0, *varargs) return output @@ -84,7 +84,7 @@ # give the repo a new UUID uuid = "01234567-89ab-cdef-89ab-cdef01234567" - svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, 1, + svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, ["SVN-fs-dump-format-version: 2\n", "\n", "UUID: ", uuid, "\n", Index: subversion/tests/cmdline/svndumpfilter_tests.py =================================================================== --- subversion/tests/cmdline/svndumpfilter_tests.py (revision 30372) +++ subversion/tests/cmdline/svndumpfilter_tests.py (working copy) @@ -46,7 +46,7 @@ ## TODO: Should we need to handle errput and exit_code? exit_code, output, errput = svntest.main.run_command_stdin( - svntest.main.svndumpfilter_binary, None, 1, dump, *varargs) + svntest.main.svndumpfilter_binary, None, dump, *varargs) return output Index: subversion/tests/cmdline/svntest/actions.py =================================================================== --- subversion/tests/cmdline/svntest/actions.py (revision 30372) +++ subversion/tests/cmdline/svntest/actions.py (working copy) @@ -121,10 +121,8 @@ def run_and_verify_svnlook(message, expected_stdout, expected_stderr, *varargs): """Like run_and_verify_svnlook2, but the expected exit code is - assumed to be 0 if no output is expected on stderr, and 1 otherwise. + assumed to be 0 if no output is expected on stderr, and 1 otherwise.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" expected_exit = 0 if expected_stderr is not None and expected_stderr != []: expected_exit = 1 @@ -133,10 +131,8 @@ def run_and_verify_svnlook2(message, expected_stdout, expected_stderr, expected_exit, *varargs): - """Run svnlook command and check its output and exit code. + """Run svnlook command and check its output and exit code.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" exit_code, out, err = main.run_svnlook(*varargs) verify.verify_outputs("Unexpected output", out, err, expected_stdout, expected_stderr) @@ -147,10 +143,8 @@ def run_and_verify_svnadmin(message, expected_stdout, expected_stderr, *varargs): """Like run_and_verify_svnadmin2, but the expected exit code is - assumed to be 0 if no output is expected on stderr, and 1 otherwise. + assumed to be 0 if no output is expected on stderr, and 1 otherwise.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" expected_exit = 0 if expected_stderr is not None and expected_stderr != []: expected_exit = 1 @@ -159,10 +153,8 @@ def run_and_verify_svnadmin2(message, expected_stdout, expected_stderr, expected_exit, *varargs): - """Run svnadmin command and check its output and exit code. + """Run svnadmin command and check its output and exit code.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" exit_code, out, err = main.run_svnadmin(*varargs) verify.verify_outputs("Unexpected output", out, err, expected_stdout, expected_stderr) @@ -173,10 +165,8 @@ def run_and_verify_svnversion(message, wc_dir, repo_url, expected_stdout, expected_stderr): """like run_and_verify_svnversion2, but the expected exit code is - assumed to be 0 if no output is expected on stderr, and 1 otherwise. + assumed to be 0 if no output is expected on stderr, and 1 otherwise.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" expected_exit = 0 if expected_stderr is not None and expected_stderr != []: expected_exit = 1 @@ -187,10 +177,8 @@ def run_and_verify_svnversion2(message, wc_dir, repo_url, expected_stdout, expected_stderr, expected_exit): - """Run svnversion command and check its output and exit code. + """Run svnversion command and check its output and exit code.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" exit_code, out, err = main.run_svnversion(wc_dir, repo_url) verify.verify_outputs("Unexpected output", out, err, expected_stdout, expected_stderr) @@ -199,11 +187,8 @@ def run_and_verify_svn(message, expected_stdout, expected_stderr, *varargs): """like run_and_verify_svn2, but the expected exit code is assumed to - be 0 if no output is expected on stderr, and 1 otherwise. + be 0 if no output is expected on stderr, and 1 otherwise.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" - expected_exit = 0 if expected_stderr is not None and expected_stderr != []: expected_exit = 1 @@ -230,10 +215,7 @@ If EXPECTED_STDOUT is None, do not check stdout. EXPECTED_STDERR may not be None. - If output checks pass, on supported platforms (namely those with the Popen3 - class), the expected and actual codes are compared. On platforms lacking - Popen3, the actual exit code is unavailable and a value of None is returned - as the exit code from this and all other run_...() functions. + If output checks pass, the expected and actual codes are compared. If a comparison fails, a Failure will be raised.""" @@ -252,10 +234,8 @@ def run_and_verify_svn_match_any(message, expected_stdout, expected_stderr, *varargs): """Like run_and_verify_svn_match_any2, but the expected exit code is - assumed to be 0 if no output is expected on stderr, and 1 otherwise. + assumed to be 0 if no output is expected on stderr, and 1 otherwise.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" expected_exit = 0 if expected_stderr is not None and expected_stderr != []: expected_exit = 1 @@ -267,11 +247,8 @@ def run_and_verify_svn_match_any2(message, expected_stdout, expected_stderr, expected_exit, *varargs): """Like run_and_verify_svn2, except that only one stdout line must match - EXPECTED_STDOUT. + EXPECTED_STDOUT.""" - Exit code is not checked on platforms without Popen3 - see note in - run_and_verify_svn2.""" - if expected_stderr is None: raise verify.SVNIncorrectDatatype("expected_stderr must not be None") @@ -290,7 +267,7 @@ "Runs 'svnadmin load' and reports any errors." expected_stderr = [] exit_code, output, errput = main.run_command_stdin( - main.svnadmin_binary, expected_stderr, 1, dump_file_content, + main.svnadmin_binary, expected_stderr, dump_file_content, 'load', '--force-uuid', '--quiet', repo_dir) verify.verify_outputs("Unexpected stderr output", None, errput, @@ -1358,7 +1335,7 @@ def check_prop(name, path, exp_out): """Verify that property NAME on PATH has a value of EXP_OUT""" # Not using run_svn because binary_mode must be set - exit_code, out, err = main.run_command(main.svn_binary, None, 1, 'pg', + exit_code, out, err = main.run_command(main.svn_binary, None, 'pg', '--strict', name, path, '--config-dir', main.default_config_dir) Index: subversion/tests/cmdline/svntest/main.py =================================================================== --- subversion/tests/cmdline/svntest/main.py (revision 30372) +++ subversion/tests/cmdline/svntest/main.py (working copy) @@ -25,6 +25,7 @@ import traceback # for print_exc() import threading import Queue +from subprocess import Popen, PIPE import getopt try: @@ -96,12 +97,6 @@ _exe = '' _bat = '' -try: - from popen2 import Popen3 - platform_with_popen3_class = True -except ImportError: - platform_with_popen3_class = False - # The location of our mock svneditor script. if sys.platform == 'win32': svneditor_script = os.path.join(sys.path[0], 'svneditor.bat') @@ -305,13 +300,12 @@ return os.path.join(repo_dir, "conf", "svnserve.conf") # Run any binary, logging the command line and return code -def run_command(command, error_expected, binary_mode=0, *varargs): +def run_command(command, error_expected, *varargs): """Run COMMAND with VARARGS; return exit code as int; stdout, stderr as lists of lines. If ERROR_EXPECTED is None, any stderr also will be printed.""" - return run_command_stdin(command, error_expected, binary_mode, - None, *varargs) + return run_command_stdin(command, error_expected, None, *varargs) # A regular expression that matches arguments that are trivially safe # to pass on a command line without quoting on any supported operating @@ -339,18 +333,16 @@ arg = arg.replace('$', '\$') return '"%s"' % (arg,) -def open_pipe(command, mode): - """Opens a popen3 pipe to COMMAND in MODE. +def open_pipe(command): + """Opens a subprocess pipe to COMMAND. Returns (infile, outfile, errfile, waiter); waiter should be passed to wait_on_pipe.""" - if platform_with_popen3_class: - kid = Popen3(command, True) - return kid.tochild, kid.fromchild, kid.childerr, (kid, command) - else: - inf, outf, errf = os.popen3(command, mode) - return inf, outf, errf, None + kid = Popen(command, shell=True, bufsize=-1, + stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + return kid.stdin, kid.stdout, kid.stderr, (kid, command) + def wait_on_pipe(waiter, stdout_lines, stderr_lines): """Waits for KID (opened with open_pipe) to finish, dying if it does. Uses STDOUT_LINES and STDERR_LINES for error message @@ -360,10 +352,10 @@ kid, command = waiter - wait_code = kid.wait() + exit_code = kid.wait() - if os.WIFSIGNALED(wait_code): - exit_signal = os.WTERMSIG(wait_code) + if exit_code < 0: + exit_signal = abs(exit_code) if stdout_lines is not None: sys.stdout.write("".join(stdout_lines)) if stderr_lines is not None: @@ -374,26 +366,20 @@ % (command, exit_signal)) raise SVNProcessTerminatedBySignal else: - exit_code = os.WEXITSTATUS(wait_code) if exit_code and verbose_mode: sys.stderr.write("CMD: %s exited with %d\n" % (command, exit_code)) return exit_code # Run any binary, supplying input text, logging the command line -def spawn_process(command, binary_mode=0,stdin_lines=None, *varargs): +def spawn_process(command, stdin_lines=None, *varargs): args = ' '.join(map(_quote_arg, varargs)) # Log the command line if verbose_mode and not command.endswith('.py'): print 'CMD:', os.path.basename(command) + ' ' + args, - if binary_mode: - mode = 'b' - else: - mode = 't' + infile, outfile, errfile, kid = open_pipe(command + ' ' + args) - infile, outfile, errfile, kid = open_pipe(command + ' ' + args, mode) - if stdin_lines: map(infile.write, stdin_lines) @@ -409,8 +395,7 @@ return exit_code, stdout_lines, stderr_lines -def run_command_stdin(command, error_expected, binary_mode=0, - stdin_lines=None, *varargs): +def run_command_stdin(command, error_expected, stdin_lines=None, *varargs): """Run COMMAND with VARARGS; input STDIN_LINES (a list of strings which should include newline characters) to program via stdin - this should not be very large, as if the program outputs more than the OS @@ -423,7 +408,6 @@ start = time.time() exit_code, stdout_lines, stderr_lines = spawn_process(command, - binary_mode, stdin_lines, *varargs) @@ -492,30 +476,30 @@ If ERROR_EXPECTED is None, any stderr also will be printed. If you're just checking that something does/doesn't come out of stdout/stderr, you might want to use actions.run_and_verify_svn().""" - return run_command(svn_binary, error_expected, 0, + return run_command(svn_binary, error_expected, *(_with_auth(_with_config_dir(varargs)))) # For running svnadmin. Ignores the output. def run_svnadmin(*varargs): """Run svnadmin with VARARGS, returns exit code as int; stdout, stderr as list of lines.""" - return run_command(svnadmin_binary, 1, 0, *varargs) + return run_command(svnadmin_binary, 1, *varargs) # For running svnlook. Ignores the output. def run_svnlook(*varargs): """Run svnlook with VARARGS, returns exit code as int; stdout, stderr as list of lines.""" - return run_command(svnlook_binary, 1, 0, *varargs) + return run_command(svnlook_binary, 1, *varargs) def run_svnsync(*varargs): """Run svnsync with VARARGS, returns exit code as int; stdout, stderr as list of lines.""" - return run_command(svnsync_binary, 1, 0, *(_with_config_dir(varargs))) + return run_command(svnsync_binary, 1, *(_with_config_dir(varargs))) def run_svnversion(*varargs): """Run svnversion with VARARGS, returns exit code as int; stdout, stderr as list of lines.""" - return run_command(svnversion_binary, 1, 0, *varargs) + return run_command(svnversion_binary, 1, *varargs) # Chmod recursively on a whole subtree def chmod_tree(path, mode, mask): @@ -601,7 +585,7 @@ opts += ("--pre-1.5-compatible",) if fs_type is not None: opts += ("--fs-type=" + fs_type,) - exit_code, stdout, stderr = run_command(svnadmin_binary, 1, 0, "create", + exit_code, stdout, stderr = run_command(svnadmin_binary, 1, "create", path, *opts) # Skip tests if we can't create the repository. @@ -644,9 +628,9 @@ start = time.time() dump_in, dump_out, dump_err, dump_kid = \ - open_pipe(svnadmin_binary + dump_args, 'b') + open_pipe(svnadmin_binary + dump_args) load_in, load_out, load_err, load_kid = \ - open_pipe(svnadmin_binary + load_args, 'b') + open_pipe(svnadmin_binary + load_args) stop = time.time() if verbose_mode: print '