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():
902
935
if not os.path.isfile(bzr_path):
903
936
# We are probably installed. Assume sys.argv is the right file
904
937
bzr_path = sys.argv[0]
908
940
# win32 subprocess doesn't support preexec_fn
909
941
# so we will avoid using it on all platforms, just to
910
942
# make sure the code path is used, and we don't break on win32
911
943
cleanup_environment()
912
process = Popen([sys.executable, bzr_path]+args,
944
process = Popen([sys.executable, bzr_path] + list(process_args),
913
945
stdout=PIPE, stderr=PIPE)
915
947
restore_environment()
917
out = process.stdout.read()
918
err = process.stderr.read()
920
if kwargs.get('universal_newlines', False):
950
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
951
universal_newlines=False, process_args=None):
952
"""Finish the execution of process.
954
:param process: the Popen object returned from start_bzr_subprocess.
955
:param retcode: The status code that is expected. Defaults to 0. If
956
None is supplied, the status code is not checked.
957
:param send_signal: an optional signal to send to the process.
958
:param universal_newlines: Convert CRLF => LF
959
:returns: (stdout, stderr)
961
if send_signal is not None:
962
os.kill(process.pid, send_signal)
963
out, err = process.communicate()
965
if universal_newlines:
921
966
out = out.replace('\r\n', '\n')
922
967
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))
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))
932
976
return [out, err]
934
978
def check_inventory_shape(self, inv, shape):