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