Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / third_party / android_testrunner / run_command.py
blob812037d9a9eee008b131501b989d02959a0bdb46
1 #!/usr/bin/python2.4
4 # Copyright 2007, The Android Open Source Project
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 # System imports
19 import os
20 import signal
21 import subprocess
22 import threading
23 import time
25 # local imports
26 import errors
27 import logger
29 _abort_on_error = False
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
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.
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
65 def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
66 """Spawns a subprocess to run the given shell command.
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 global _abort_on_error, error_occurred
84 error_occurred = False
86 if return_output:
87 output_dest = subprocess.PIPE
88 else:
89 # None means direct to stdout
90 output_dest = None
91 if stdin_input:
92 stdin_dest = subprocess.PIPE
93 else:
94 stdin_dest = None
95 pipe = subprocess.Popen(
96 cmd,
97 executable='/bin/bash',
98 stdin=stdin_dest,
99 stdout=output_dest,
100 stderr=subprocess.STDOUT,
101 shell=True)
103 def Run():
104 global error_occurred
105 try:
106 output = pipe.communicate(input=stdin_input)[0]
107 if output is not None and len(output) > 0:
108 so.append(output)
109 except OSError, e:
110 logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
111 logger.Log(e)
112 so.append("ERROR")
113 error_occurred = True
114 if pipe.returncode:
115 logger.SilentLog("Error: %s returned %d error code" %(cmd,
116 pipe.returncode))
117 error_occurred = True
119 t = threading.Thread(target=Run)
120 t.start()
121 t.join(timeout_time)
122 if t.isAlive():
123 try:
124 pipe.kill()
125 except OSError:
126 # Can't kill a dead process.
127 pass
128 finally:
129 logger.SilentLog("about to raise a timeout for: %s" % cmd)
130 raise errors.WaitForResponseTimedOutError
132 output = "".join(so)
133 if _abort_on_error and error_occurred:
134 raise errors.AbortError(msg=output)
136 return "".join(so)
139 def RunHostCommand(binary, valgrind=False):
140 """Run a command on the host (opt using valgrind).
142 Runs the host binary and returns the exit code.
143 If successfull, the output (stdout and stderr) are discarded,
144 but printed in case of error.
145 The command can be run under valgrind in which case all the
146 output are always discarded.
148 Args:
149 binary: full path of the file to be run.
150 valgrind: If True the command will be run under valgrind.
152 Returns:
153 The command exit code (int)
155 if not valgrind:
156 subproc = subprocess.Popen(binary, stdout=subprocess.PIPE,
157 stderr=subprocess.STDOUT)
158 subproc.wait()
159 if subproc.returncode != 0: # In case of error print the output
160 print subproc.communicate()[0]
161 return subproc.returncode
162 else:
163 # Need the full path to valgrind to avoid other versions on the system.
164 subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
165 "--leak-check=yes", "-q", binary],
166 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
167 # Cannot rely on the retcode of valgrind. Instead look for an empty output.
168 valgrind_out = subproc.communicate()[0].strip()
169 if valgrind_out:
170 print valgrind_out
171 return 1
172 else:
173 return 0
176 def HasValgrind():
177 """Check that /usr/bin/valgrind exists.
179 We look for the fullpath to avoid picking up 'alternative' valgrind
180 on the system.
182 Returns:
183 True if a system valgrind was found.
185 return os.path.exists("/usr/bin/valgrind")