Index: third_party/gtest-parallel/gtest-parallel |
diff --git a/third_party/gtest-parallel/gtest-parallel b/third_party/gtest-parallel/gtest-parallel |
index 0be59e4b4e06af03d4cdb318206e97bc215f27e8..64fbb1c4c216e076665e54b6ff0f462ed7d455b2 100755 |
--- a/third_party/gtest-parallel/gtest-parallel |
+++ b/third_party/gtest-parallel/gtest-parallel |
@@ -13,12 +13,14 @@ |
# See the License for the specific language governing permissions and |
# limitations under the License. |
import cPickle |
+import errno |
import gzip |
import multiprocessing |
import optparse |
import os |
import subprocess |
import sys |
+import tempfile |
import threading |
import time |
import zlib |
@@ -62,6 +64,10 @@ class Outputter(object): |
stdout_lock = threading.Lock() |
class FilterFormat: |
+ if sys.stdout.isatty(): |
+ # stdout needs to be unbuffered since the output is interactive. |
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) |
+ |
out = Outputter(sys.stdout) |
total_tests = 0 |
finished_tests = 0 |
@@ -80,7 +86,6 @@ class FilterFormat: |
if command == "TEST": |
(binary, test) = arg.split(' ', 1) |
self.tests[job_id] = (binary, test.strip()) |
- self.outputs[job_id] = [] |
elif command == "EXIT": |
(exit_code, time_ms) = [int(x) for x in arg.split(' ', 1)] |
self.finished_tests += 1 |
@@ -88,8 +93,9 @@ class FilterFormat: |
self.print_test_status(test, time_ms) |
if exit_code != 0: |
self.failures.append(self.tests[job_id]) |
- for line in self.outputs[job_id]: |
- self.out.permanent_line(line) |
+ with open(self.outputs[job_id]) as f: |
+ for line in f.readlines(): |
+ self.out.permanent_line(line.rstrip()) |
self.out.permanent_line( |
"[%d/%d] %s returned/aborted with exit code %d (%d ms)" |
% (self.finished_tests, self.total_tests, test, exit_code, time_ms)) |
@@ -97,17 +103,15 @@ class FilterFormat: |
self.total_tests = int(arg.split(' ', 1)[1]) |
self.out.transient_line("[0/%d] Running tests..." % self.total_tests) |
- def add_stdout(self, job_id, output): |
- self.outputs[job_id].append(output) |
+ def logfile(self, job_id, name): |
+ self.outputs[job_id] = name |
def log(self, line): |
stdout_lock.acquire() |
(prefix, output) = line.split(' ', 1) |
- if prefix[-1] == ':': |
- self.handle_meta(int(prefix[:-1]), output) |
- else: |
- self.add_stdout(int(prefix[:-1]), output) |
+ assert prefix[-1] == ':' |
+ self.handle_meta(int(prefix[:-1]), output) |
stdout_lock.release() |
def end(self): |
@@ -123,6 +127,10 @@ class RawFormat: |
sys.stdout.write(line + "\n") |
sys.stdout.flush() |
stdout_lock.release() |
+ def logfile(self, job_id, name): |
+ with open(self.outputs[job_id]) as f: |
+ for line in f.readlines(): |
+ self.log(str(job_id) + '> ' + line.rstrip()) |
def end(self): |
pass |
@@ -184,6 +192,9 @@ for i in range(len(sys.argv)): |
parser = optparse.OptionParser( |
usage = 'usage: %prog [options] binary [binary ...] -- [additional args]') |
+parser.add_option('-d', '--output_dir', type='string', |
+ default=os.path.join(tempfile.gettempdir(), "gtest-parallel"), |
+ help='output directory for test logs') |
parser.add_option('-r', '--repeat', type='int', default=1, |
help='repeat tests') |
parser.add_option('-w', '--workers', type='int', |
@@ -260,25 +271,33 @@ logger.log(str(-1) + ': TESTCNT ' + ' ' + str(len(tests))) |
exit_code = 0 |
+# Create directory for test log output. |
+try: |
+ os.makedirs(options.output_dir) |
+except OSError as e: |
+ # Ignore errors if this directory already exists. |
+ if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir): |
+ raise e |
+# Remove files from old test runs. |
+for logfile in os.listdir(options.output_dir): |
+ os.remove(os.path.join(options.output_dir, logfile)) |
+ |
# Run the specified job. Return the elapsed time in milliseconds if |
# the job succeeds, or a very large number (larger than any reasonable |
# elapsed time) if the job fails. (This ensures that failing tests |
# will run first the next time.) |
def run_job((command, job_id, test)): |
begin = time.time() |
- sub = subprocess.Popen(command + ['--gtest_filter=' + test] + |
- ['--gtest_color=' + options.gtest_color], |
- stdout = subprocess.PIPE, |
- stderr = subprocess.STDOUT) |
- while True: |
- line = sub.stdout.readline() |
- if line == '': |
- break |
- logger.log(str(job_id) + '> ' + line.rstrip()) |
+ with tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) as log: |
+ sub = subprocess.Popen(command + ['--gtest_filter=' + test] + |
+ ['--gtest_color=' + options.gtest_color], |
+ stdout=log.file, |
+ stderr=log.file) |
+ code = sub.wait() |
+ runtime_ms = int(1000 * (time.time() - begin)) |
+ logger.logfile(job_id, log.name) |
- code = sub.wait() |
- runtime_ms = int(1000 * (time.time() - begin)) |
logger.log("%s: EXIT %s %d" % (job_id, code, runtime_ms)) |
if code == 0: |
return runtime_ms |