OSDN Git Service

Remove use of deprecated API from test sample code.
[android-x86/development.git] / testrunner / run_command.py
1 #!/usr/bin/python2.4
2 #
3 #
4 # Copyright 2007, The Android Open Source Project
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #     http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # System imports
19 import os
20 import signal
21 import subprocess
22 import threading
23 import time
24
25 # local imports
26 import errors
27 import logger
28
29 _abort_on_error = False
30
31 def SetAbortOnError(abort=True):
32   """Sets behavior of RunCommand to throw AbortError if command process returns
33   a negative error code"""
34   global _abort_on_error
35   _abort_on_error = abort
36
37 def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True,
38                stdin_input=None):
39   """Spawn and retry a subprocess to run the given shell command.
40
41   Args:
42     cmd: shell command to run
43     timeout_time: time in seconds to wait for command to run before aborting.
44     retry_count: number of times to retry command
45     return_output: if True return output of command as string. Otherwise,
46       direct output of command to stdout.
47     stdin_input: data to feed to stdin
48   Returns:
49     output of command
50   """
51   result = None
52   while True:
53     try:
54       result = RunOnce(cmd, timeout_time=timeout_time,
55                        return_output=return_output, stdin_input=stdin_input)
56     except errors.WaitForResponseTimedOutError:
57       if retry_count == 0:
58         raise
59       retry_count -= 1
60       logger.Log("No response for %s, retrying" % cmd)
61     else:
62       # Success
63       return result
64
65 def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
66   """Spawns a subprocess to run the given shell command.
67
68   Args:
69     cmd: shell command to run
70     timeout_time: time in seconds to wait for command to run before aborting.
71     return_output: if True return output of command as string. Otherwise,
72       direct output of command to stdout.
73     stdin_input: data to feed to stdin
74   Returns:
75     output of command
76   Raises:
77     errors.WaitForResponseTimedOutError if command did not complete within
78       timeout_time seconds.
79     errors.AbortError is command returned error code and SetAbortOnError is on.
80   """
81   start_time = time.time()
82   so = []
83   pid = []
84   global _abort_on_error, error_occurred
85   error_occurred = False
86
87   def Run():
88     global error_occurred
89     if return_output:
90       output_dest = subprocess.PIPE
91     else:
92       # None means direct to stdout
93       output_dest = None
94     if stdin_input:
95       stdin_dest = subprocess.PIPE
96     else:
97       stdin_dest = None
98     pipe = subprocess.Popen(
99         cmd,
100         executable='/bin/bash',
101         stdin=stdin_dest,
102         stdout=output_dest,
103         stderr=subprocess.STDOUT,
104         shell=True)
105     pid.append(pipe.pid)
106     try:
107       output = pipe.communicate(input=stdin_input)[0]
108       if output is not None and len(output) > 0:
109         so.append(output)
110     except OSError, e:
111       logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
112       logger.Log(e)
113       so.append("ERROR")
114       error_occurred = True
115     if pipe.returncode:
116       logger.SilentLog("Error: %s returned %d error code" %(cmd,
117           pipe.returncode))
118       error_occurred = True
119
120   t = threading.Thread(target=Run)
121   t.start()
122
123   break_loop = False
124   while not break_loop:
125     if not t.isAlive():
126       break_loop = True
127
128     # Check the timeout
129     if (not break_loop and timeout_time is not None
130         and time.time() > start_time + timeout_time):
131       try:
132         os.kill(pid[0], signal.SIGKILL)
133       except OSError:
134         # process already dead. No action required.
135         pass
136
137       logger.SilentLog("about to raise a timeout for: %s" % cmd)
138       raise errors.WaitForResponseTimedOutError
139     if not break_loop:
140       time.sleep(0.1)
141
142   t.join()
143   output = "".join(so)
144   if _abort_on_error and error_occurred:
145     raise errors.AbortError(msg=output)
146
147   return "".join(so)
148
149
150 def RunHostCommand(binary, valgrind=False):
151   """Run a command on the host (opt using valgrind).
152
153   Runs the host binary and returns the exit code.
154   If successfull, the output (stdout and stderr) are discarded,
155   but printed in case of error.
156   The command can be run under valgrind in which case all the
157   output are always discarded.
158
159   Args:
160     binary: full path of the file to be run.
161     valgrind: If True the command will be run under valgrind.
162
163   Returns:
164     The command exit code (int)
165   """
166   if not valgrind:
167     subproc = subprocess.Popen(binary, stdout=subprocess.PIPE,
168                                stderr=subprocess.STDOUT)
169     subproc.wait()
170     if subproc.returncode != 0:         # In case of error print the output
171       print subproc.communicate()[0]
172     return subproc.returncode
173   else:
174     # Need the full path to valgrind to avoid other versions on the system.
175     subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
176                                 "--leak-check=yes", "-q", binary],
177                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
178     # Cannot rely on the retcode of valgrind. Instead look for an empty output.
179     valgrind_out = subproc.communicate()[0].strip()
180     if valgrind_out:
181       print valgrind_out
182       return 1
183     else:
184       return 0
185
186
187 def HasValgrind():
188   """Check that /usr/bin/valgrind exists.
189
190   We look for the fullpath to avoid picking up 'alternative' valgrind
191   on the system.
192
193   Returns:
194     True if a system valgrind was found.
195   """
196   return os.path.exists("/usr/bin/valgrind")