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 logging
     30 import os
     31 import StringIO
     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 # FIXME: This should be unified with MockExecutive2
     50 class MockExecutive(object):
     51     PIPE = "MOCK PIPE"
     52     STDOUT = "MOCK STDOUT"
     53 
     54     @staticmethod
     55     def ignore_error(error):
     56         pass
     57 
     58     def __init__(self, should_log=False, should_throw=False, should_throw_when_run=None):
     59         self._should_log = should_log
     60         self._should_throw = should_throw
     61         self._should_throw_when_run = should_throw_when_run or set()
     62         # FIXME: Once executive wraps os.getpid() we can just use a static pid for "this" process.
     63         self._running_pids = {'test-webkitpy': os.getpid()}
     64         self._proc = None
     65         self.calls = []
     66 
     67     def check_running_pid(self, pid):
     68         return pid in self._running_pids.values()
     69 
     70     def running_pids(self, process_name_filter):
     71         running_pids = []
     72         for process_name, process_pid in self._running_pids.iteritems():
     73             if process_name_filter(process_name):
     74                 running_pids.append(process_pid)
     75 
     76         _log.info("MOCK running_pids: %s" % running_pids)
     77         return running_pids
     78 
     79     def run_and_throw_if_fail(self, args, quiet=False, cwd=None, env=None):
     80         if self._should_log:
     81             env_string = ""
     82             if env:
     83                 env_string = ", env=%s" % env
     84             _log.info("MOCK run_and_throw_if_fail: %s, cwd=%s%s" % (args, cwd, env_string))
     85         if self._should_throw_when_run.intersection(args):
     86             raise ScriptError("Exception for %s" % args, output="MOCK command output")
     87         return "MOCK output of child process"
     88 
     89     def command_for_printing(self, args):
     90         string_args = map(unicode, args)
     91         return " ".join(string_args)
     92 
     93     def run_command(self,
     94                     args,
     95                     cwd=None,
     96                     input=None,
     97                     error_handler=None,
     98                     return_exit_code=False,
     99                     return_stderr=True,
    100                     decode_output=False,
    101                     env=None,
    102                     debug_logging=False):
    103 
    104         self.calls.append(args)
    105 
    106         assert(isinstance(args, list) or isinstance(args, tuple))
    107         if self._should_log:
    108             env_string = ""
    109             if env:
    110                 env_string = ", env=%s" % env
    111             input_string = ""
    112             if input:
    113                 input_string = ", input=%s" % input
    114             _log.info("MOCK run_command: %s, cwd=%s%s%s" % (args, cwd, env_string, input_string))
    115         output = "MOCK output of child process"
    116 
    117         if self._should_throw_when_run.intersection(args):
    118             raise ScriptError("Exception for %s" % args, output="MOCK command output")
    119 
    120         if self._should_throw:
    121             raise ScriptError("MOCK ScriptError", output=output)
    122         return output
    123 
    124     def cpu_count(self):
    125         return 2
    126 
    127     def kill_all(self, process_name):
    128         pass
    129 
    130     def kill_process(self, pid):
    131         pass
    132 
    133     def popen(self, args, cwd=None, env=None, **kwargs):
    134         self.calls.append(args)
    135         if self._should_log:
    136             cwd_string = ""
    137             if cwd:
    138                 cwd_string = ", cwd=%s" % cwd
    139             env_string = ""
    140             if env:
    141                 env_string = ", env=%s" % env
    142             _log.info("MOCK popen: %s%s%s" % (args, cwd_string, env_string))
    143         if not self._proc:
    144             self._proc = MockProcess()
    145         return self._proc
    146 
    147     def call(self, args, **kwargs):
    148         _log.info('Mock call: %s' % args)
    149 
    150     def run_in_parallel(self, commands):
    151         assert len(commands)
    152 
    153         num_previous_calls = len(self.calls)
    154         command_outputs = []
    155         for cmd_line, cwd in commands:
    156             command_outputs.append([0, self.run_command(cmd_line, cwd=cwd), ''])
    157 
    158         new_calls = self.calls[num_previous_calls:]
    159         self.calls = self.calls[:num_previous_calls]
    160         self.calls.append(new_calls)
    161         return command_outputs
    162 
    163 
    164 class MockExecutive2(MockExecutive):
    165     """MockExecutive2 is like MockExecutive except it doesn't log anything."""
    166 
    167     def __init__(self, output='', exit_code=0, exception=None, run_command_fn=None, stderr=''):
    168         self._output = output
    169         self._stderr = stderr
    170         self._exit_code = exit_code
    171         self._exception = exception
    172         self._run_command_fn = run_command_fn
    173         self.calls = []
    174 
    175     def run_command(self,
    176                     args,
    177                     cwd=None,
    178                     input=None,
    179                     error_handler=None,
    180                     return_exit_code=False,
    181                     return_stderr=True,
    182                     decode_output=False,
    183                     env=None,
    184                     debug_logging=False):
    185         self.calls.append(args)
    186         assert(isinstance(args, list) or isinstance(args, tuple))
    187         if self._exception:
    188             raise self._exception  # pylint: disable=E0702
    189         if self._run_command_fn:
    190             return self._run_command_fn(args)
    191         if return_exit_code:
    192             return self._exit_code
    193         if self._exit_code and error_handler:
    194             script_error = ScriptError(script_args=args, exit_code=self._exit_code, output=self._output)
    195             error_handler(script_error)
    196         if return_stderr:
    197             return self._output + self._stderr
    198         return self._output
    199