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 
    103         self.calls.append(args)
    104 
    105         assert(isinstance(args, list) or isinstance(args, tuple))
    106         if self._should_log:
    107             env_string = ""
    108             if env:
    109                 env_string = ", env=%s" % env
    110             input_string = ""
    111             if input:
    112                 input_string = ", input=%s" % input
    113             _log.info("MOCK run_command: %s, cwd=%s%s%s" % (args, cwd, env_string, input_string))
    114         output = "MOCK output of child process"
    115 
    116         if self._should_throw_when_run.intersection(args):
    117             raise ScriptError("Exception for %s" % args, output="MOCK command output")
    118 
    119         if self._should_throw:
    120             raise ScriptError("MOCK ScriptError", output=output)
    121         return output
    122 
    123     def cpu_count(self):
    124         return 2
    125 
    126     def kill_all(self, process_name):
    127         pass
    128 
    129     def kill_process(self, pid):
    130         pass
    131 
    132     def popen(self, args, cwd=None, env=None, **kwargs):
    133         self.calls.append(args)
    134         if self._should_log:
    135             cwd_string = ""
    136             if cwd:
    137                 cwd_string = ", cwd=%s" % cwd
    138             env_string = ""
    139             if env:
    140                 env_string = ", env=%s" % env
    141             _log.info("MOCK popen: %s%s%s" % (args, cwd_string, env_string))
    142         if not self._proc:
    143             self._proc = MockProcess()
    144         return self._proc
    145 
    146     def call(self, args, **kwargs):
    147         _log.info('Mock call: %s' % args)
    148 
    149     def run_in_parallel(self, commands):
    150         num_previous_calls = len(self.calls)
    151         command_outputs = []
    152         for cmd_line, cwd in commands:
    153             command_outputs.append([0, self.run_command(cmd_line, cwd=cwd), ''])
    154 
    155         new_calls = self.calls[num_previous_calls:]
    156         self.calls = self.calls[:num_previous_calls]
    157         self.calls.append(new_calls)
    158         return command_outputs
    159 
    160 
    161 class MockExecutive2(MockExecutive):
    162     """MockExecutive2 is like MockExecutive except it doesn't log anything."""
    163 
    164     def __init__(self, output='', exit_code=0, exception=None, run_command_fn=None, stderr=''):
    165         self._output = output
    166         self._stderr = stderr
    167         self._exit_code = exit_code
    168         self._exception = exception
    169         self._run_command_fn = run_command_fn
    170         self.calls = []
    171 
    172     def run_command(self,
    173                     args,
    174                     cwd=None,
    175                     input=None,
    176                     error_handler=None,
    177                     return_exit_code=False,
    178                     return_stderr=True,
    179                     decode_output=False,
    180                     env=None):
    181         self.calls.append(args)
    182         assert(isinstance(args, list) or isinstance(args, tuple))
    183         if self._exception:
    184             raise self._exception  # pylint: disable=E0702
    185         if self._run_command_fn:
    186             return self._run_command_fn(args)
    187         if return_exit_code:
    188             return self._exit_code
    189         if self._exit_code and error_handler:
    190             script_error = ScriptError(script_args=args, exit_code=self._exit_code, output=self._output)
    191             error_handler(script_error)
    192         if return_stderr:
    193             return self._output + self._stderr
    194         return self._output
    195