Home | History | Annotate | Download | only in system
      1 # Copyright (C) 2011 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #    * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #    * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #    * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 import StringIO
     30 import logging
     31 import os
     32 
     33 from webkitpy.common.system.executive import ScriptError
     34 
     35 _log = logging.getLogger(__name__)
     36 
     37 
     38 class MockProcess(object):
     39     def __init__(self, stdout='MOCK STDOUT\n', stderr=''):
     40         self.pid = 42
     41         self.stdout = StringIO.StringIO(stdout)
     42         self.stderr = StringIO.StringIO(stderr)
     43         self.stdin = StringIO.StringIO()
     44         self.returncode = 0
     45 
     46     def wait(self):
     47         return
     48 
     49     def poll(self):
     50         # Consider the process completed when all the stdout and stderr has been read.
     51         if self.stdout.len != self.stdout.tell() or self.stderr.len != self.stderr.tell():
     52             return None
     53         return self.returncode
     54 
     55 # FIXME: This should be unified with MockExecutive2
     56 class MockExecutive(object):
     57     PIPE = "MOCK PIPE"
     58     STDOUT = "MOCK STDOUT"
     59 
     60     @staticmethod
     61     def ignore_error(error):
     62         pass
     63 
     64     def __init__(self, should_log=False, should_throw=False, should_throw_when_run=None):
     65         self._should_log = should_log
     66         self._should_throw = should_throw
     67         self._should_throw_when_run = should_throw_when_run or set()
     68         # FIXME: Once executive wraps os.getpid() we can just use a static pid for "this" process.
     69         self._running_pids = {'test-webkitpy': os.getpid()}
     70         self._proc = None
     71         self.calls = []
     72 
     73     def check_running_pid(self, pid):
     74         return pid in self._running_pids.values()
     75 
     76     def running_pids(self, process_name_filter):
     77         running_pids = []
     78         for process_name, process_pid in self._running_pids.iteritems():
     79             if process_name_filter(process_name):
     80                 running_pids.append(process_pid)
     81 
     82         _log.info("MOCK running_pids: %s" % running_pids)
     83         return running_pids
     84 
     85     def run_and_throw_if_fail(self, args, quiet=False, cwd=None, env=None):
     86         self.calls.append(args)
     87         if self._should_log:
     88             env_string = ""
     89             if env:
     90                 env_string = ", env=%s" % env
     91             _log.info("MOCK run_and_throw_if_fail: %s, cwd=%s%s" % (args, cwd, env_string))
     92         if self._should_throw_when_run.intersection(args):
     93             raise ScriptError("Exception for %s" % args, output="MOCK command output")
     94         return "MOCK output of child process"
     95 
     96     def command_for_printing(self, args):
     97         string_args = map(unicode, args)
     98         return " ".join(string_args)
     99 
    100     def run_command(self,
    101                     args,
    102                     cwd=None,
    103                     input=None,
    104                     error_handler=None,
    105                     return_exit_code=False,
    106                     return_stderr=True,
    107                     decode_output=False,
    108                     env=None,
    109                     debug_logging=False):
    110 
    111         self.calls.append(args)
    112 
    113         assert(isinstance(args, list) or isinstance(args, tuple))
    114         if self._should_log:
    115             env_string = ""
    116             if env:
    117                 env_string = ", env=%s" % env
    118             input_string = ""
    119             if input:
    120                 input_string = ", input=%s" % input
    121             _log.info("MOCK run_command: %s, cwd=%s%s%s" % (args, cwd, env_string, input_string))
    122         output = "MOCK output of child process"
    123 
    124         if self._should_throw_when_run.intersection(args):
    125             raise ScriptError("Exception for %s" % args, output="MOCK command output")
    126 
    127         if self._should_throw:
    128             raise ScriptError("MOCK ScriptError", output=output)
    129         return output
    130 
    131     def cpu_count(self):
    132         return 2
    133 
    134     def kill_all(self, process_name):
    135         pass
    136 
    137     def kill_process(self, pid):
    138         pass
    139 
    140     def popen(self, args, cwd=None, env=None, **kwargs):
    141         self.calls.append(args)
    142         if self._should_log:
    143             cwd_string = ""
    144             if cwd:
    145                 cwd_string = ", cwd=%s" % cwd
    146             env_string = ""
    147             if env:
    148                 env_string = ", env=%s" % env
    149             _log.info("MOCK popen: %s%s%s" % (args, cwd_string, env_string))
    150         if not self._proc:
    151             self._proc = MockProcess()
    152         return self._proc
    153 
    154     def call(self, args, **kwargs):
    155         self.calls.append(args)
    156         _log.info('Mock call: %s' % args)
    157 
    158     def run_in_parallel(self, commands):
    159         assert len(commands)
    160 
    161         num_previous_calls = len(self.calls)
    162         command_outputs = []
    163         for cmd_line, cwd in commands:
    164             command_outputs.append([0, self.run_command(cmd_line, cwd=cwd), ''])
    165 
    166         new_calls = self.calls[num_previous_calls:]
    167         self.calls = self.calls[:num_previous_calls]
    168         self.calls.append(new_calls)
    169         return command_outputs
    170 
    171     def map(self, thunk, arglist, processes=None):
    172         return map(thunk, arglist)
    173 
    174 
    175 class MockExecutive2(MockExecutive):
    176     """MockExecutive2 is like MockExecutive except it doesn't log anything."""
    177 
    178     def __init__(self, output='', exit_code=0, exception=None, run_command_fn=None, stderr=''):
    179         self._output = output
    180         self._stderr = stderr
    181         self._exit_code = exit_code
    182         self._exception = exception
    183         self._run_command_fn = run_command_fn
    184         self.calls = []
    185 
    186     def run_command(self,
    187                     args,
    188                     cwd=None,
    189                     input=None,
    190                     error_handler=None,
    191                     return_exit_code=False,
    192                     return_stderr=True,
    193                     decode_output=False,
    194                     env=None,
    195                     debug_logging=False):
    196         self.calls.append(args)
    197         assert(isinstance(args, list) or isinstance(args, tuple))
    198         if self._exception:
    199             raise self._exception  # pylint: disable=E0702
    200         if self._run_command_fn:
    201             return self._run_command_fn(args)
    202         if return_exit_code:
    203             return self._exit_code
    204         if self._exit_code and error_handler:
    205             script_error = ScriptError(script_args=args, exit_code=self._exit_code, output=self._output)
    206             error_handler(script_error)
    207         if return_stderr:
    208             return self._output + self._stderr
    209         return self._output
    210