887
887
:param universal_newlines: Convert CRLF => LF
889
889
env_changes = kwargs.get('env_changes', {})
890
process = self.start_bzr_subprocess(args, env_changes=env_changes)
891
# We distinguish between retcode=None and retcode not passed.
892
supplied_retcode = kwargs.get('retcode', 0)
893
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
894
universal_newlines=kwargs.get('universal_newlines', False),
897
def start_bzr_subprocess(self, process_args, env_changes=None,
898
skip_if_plan_to_signal=False):
899
"""Start bzr in a subprocess for testing.
901
This starts a new Python interpreter and runs bzr in there.
902
This should only be used for tests that have a justifiable need for
903
this isolation: e.g. they are testing startup time, or signal
904
handling, or early startup code, etc. Subprocess code can't be
905
profiled or debugged so easily.
907
:param process_args: a list of arguments to pass to the bzr executable,
908
for example `['--version']`.
909
:param env_changes: A dictionary which lists changes to environment
910
variables. A value of None will unset the env variable.
911
The values must be strings. The change will only occur in the
912
child, so you don't need to fix the environment after running.
913
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
916
:returns: Popen object for the started process.
918
if skip_if_plan_to_signal:
919
if not getattr(os, 'kill', None):
920
raise TestSkipped("os.kill not available.")
922
if env_changes is None:
893
926
def cleanup_environment():
899
932
osutils.set_or_unset_env(env_var, value)
901
934
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
935
if not os.path.isfile(bzr_path):
936
# We are probably installed. Assume sys.argv is the right file
937
bzr_path = sys.argv[0]
905
940
# win32 subprocess doesn't support preexec_fn
906
941
# so we will avoid using it on all platforms, just to
907
942
# make sure the code path is used, and we don't break on win32
908
943
cleanup_environment()
909
process = Popen([sys.executable, bzr_path]+args,
910
stdout=PIPE, stderr=PIPE)
944
process = Popen([sys.executable, bzr_path] + list(process_args),
945
stdin=PIPE, stdout=PIPE, stderr=PIPE)
912
947
restore_environment()
914
out = process.stdout.read()
915
err = process.stderr.read()
917
if kwargs.get('universal_newlines', False):
918
out = out.replace('\r\n', '\n')
919
err = err.replace('\r\n', '\n')
921
retcode = process.wait()
922
supplied_retcode = kwargs.get('retcode', 0)
923
if supplied_retcode is not None:
924
assert supplied_retcode == retcode
927
def start_bzr_subprocess(self, *args):
928
"""Start bzr in a subprocess for testing.
930
This starts a new Python interpreter and runs bzr in there.
931
This should only be used for tests that have a justifiable need for
932
this isolation: e.g. they are testing startup time, or signal
933
handling, or early startup code, etc. Subprocess code can't be
934
profiled or debugged so easily.
936
:returns: Popen object for the started process.
938
# TODO: this ought to remove BZR_PDB when running the subprocess- the
939
# user probably doesn't want to debug it, and anyhow since its files
940
# are redirected they can't usefully get at it. It just makes the
942
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
944
process = Popen([sys.executable, bzr_path]+args, stdout=PIPE,
948
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None):
950
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
951
universal_newlines=False, process_args=None):
949
952
"""Finish the execution of process.
951
954
:param process: the Popen object returned from start_bzr_subprocess.
952
:param retcode: the expected return code of the process, if None any
953
value is accepted, otherwise if there is a difference a failure will
955
:param retcode: The status code that is expected. Defaults to 0. If
956
None is supplied, the status code is not checked.
955
957
:param send_signal: an optional signal to send to the process.
958
:param universal_newlines: Convert CRLF => LF
956
959
:returns: (stdout, stderr)
958
961
if send_signal is not None:
959
962
os.kill(process.pid, send_signal)
960
result = process.communicate()
961
if retcode is not None:
962
self.assertEqual(retcode, process.returncode)
963
out, err = process.communicate()
965
if universal_newlines:
966
out = out.replace('\r\n', '\n')
967
err = err.replace('\r\n', '\n')
969
if retcode is not None and retcode != process.returncode:
970
if process_args is None:
971
process_args = "(unknown args)"
972
mutter('Output of bzr %s:\n%s', process_args, out)
973
mutter('Error for bzr %s:\n%s', process_args, err)
974
self.fail('Command bzr %s failed with retcode %s != %s'
975
% (process_args, retcode, process.returncode))
965
978
def check_inventory_shape(self, inv, shape):
966
979
"""Compare an inventory to a list of expected names.