~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

(Andrew Bennetts, Robert Collins) Create a new test helper start_bzr_subprocess which is paired with finish_bzr_subprocess, allowing tests that need to interact with the upcoming bzr serve command.

Show diffs side-by-side

added added

removed removed

Lines of Context:
887
887
        :param universal_newlines: Convert CRLF => LF
888
888
        """
889
889
        env_changes = kwargs.get('env_changes', {})
890
 
 
 
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),
 
895
            process_args=args)
 
896
 
 
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.
 
900
 
 
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.
 
906
 
 
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
 
914
            is not available.
 
915
 
 
916
        :returns: Popen object for the started process.
 
917
        """
 
918
        if skip_if_plan_to_signal:
 
919
            if not getattr(os, 'kill', None):
 
920
                raise TestSkipped("os.kill not available.")
 
921
 
 
922
        if env_changes is None:
 
923
            env_changes = {}
891
924
        old_env = {}
892
925
 
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]
905
 
        args = list(args)
906
938
 
907
939
        try:
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)
914
946
        finally:
915
947
            restore_environment()
916
 
            
917
 
        out = process.stdout.read()
918
 
        err = process.stderr.read()
919
 
 
920
 
        if kwargs.get('universal_newlines', False):
 
948
        return process
 
949
 
 
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.
 
953
 
 
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)
 
960
        """
 
961
        if send_signal is not None:
 
962
            os.kill(process.pid, send_signal)
 
963
        out, err = process.communicate()
 
964
 
 
965
        if universal_newlines:
921
966
            out = out.replace('\r\n', '\n')
922
967
            err = err.replace('\r\n', '\n')
923
968
 
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]
933
977
 
934
978
    def check_inventory_shape(self, inv, shape):