Index: tools/sharding_supervisor/sharding_supervisor.py |
diff --git a/tools/sharding_supervisor/sharding_supervisor.py b/tools/sharding_supervisor/sharding_supervisor.py |
index 2c4bd606dfff4ff93af21a2dc522aa393c11a026..75c0cfb68860f2f65c8c8bf682ce7a4c4cc78b78 100755 |
--- a/tools/sharding_supervisor/sharding_supervisor.py |
+++ b/tools/sharding_supervisor/sharding_supervisor.py |
@@ -81,21 +81,45 @@ class ShardRunner(threading.Thread): |
counter: Called to get the next shard index to run. |
""" |
- def __init__(self, supervisor, counter, test_fail, test_timeout): |
+ def __init__(self, supervisor, counter, test_start, test_ok, test_fail, |
+ test_timeout): |
"""Inits ShardRunner with a supervisor and counter.""" |
threading.Thread.__init__(self) |
self.supervisor = supervisor |
self.counter = counter |
+ self.test_start = test_start |
+ self.test_ok = test_ok |
self.test_fail = test_fail |
self.test_timeout = test_timeout |
+ self.current_test = "" |
- def SearchForFailure(self, regex, prefix, line, description): |
- results = regex.search(line) |
+ def ReportFailure(self, description, prefix, test_name): |
+ log_line = "%s: %s%s\n" % (description, prefix, test_name) |
+ self.supervisor.LogLineFailure(log_line) |
+ |
+ def ProcessLine(self, prefix, line): |
+ results = self.test_start.search(line) |
+ if results: |
+ if self.current_test: |
+ self.ReportFailure("CRASHED", prefix, results.group(1)) |
+ self.current_test = results.group(1) |
+ return |
+ |
+ results = self.test_ok.search(line) |
+ if results: |
+ self.current_test = "" |
+ return |
+ |
+ results = self.test_fail.search(line) |
+ if results: |
+ self.ReportFailure("FAILED", prefix, results.group(1)) |
+ self.current_test = "" |
+ return |
+ |
+ results = self.test_timeout.search(line) |
Paweł Hajdan Jr.
2011/08/15 17:33:17
Don't rely on that line to be present. It's fragil
clee
2011/08/15 18:07:09
It's what gtest_command uses to detect timeouts. T
Paweł Hajdan Jr.
2011/08/16 17:36:07
And guess what? It's broken.
|
if results: |
- log_line = "%s: %s%s\n" % (description, prefix, results.group(1)) |
- self.supervisor.LogLineFailure(log_line) |
- return True |
- return False |
+ self.ReportFailure("TIMEOUT", prefix, results.group(1)) |
+ self.current_test = "" |
def run(self): |
"""Runs shards and outputs the results. |
@@ -124,9 +148,7 @@ class ShardRunner(threading.Thread): |
line = chars.getvalue() |
if not line and not shard_running: |
break |
- if not self.SearchForFailure( |
- self.test_fail, prefix, line, "FAILED"): |
- self.SearchForFailure(self.test_timeout, prefix, line, "TIMEOUT") |
+ self.ProcessLine(prefix, line) |
line = prefix + line |
self.supervisor.LogOutputLine(index, line) |
chars.close() |
@@ -185,11 +207,14 @@ class ShardingSupervisor(object): |
test_name_regex = r"((\w+/)?\w+\.\w+(/\d+)?)" |
# Regex for filtering out ANSI escape codes when using color. |
- ansi_code_regex = r"(?:\x1b\[.*?[a-zA-Z])?" |
+ ansi_regex = r"(?:\x1b\[.*?[a-zA-Z])?" |
+ test_start = re.compile( |
+ ansi_regex + "\[\s+RUN\s+\] " + ansi_regex + test_name_regex) |
M-A Ruel
2011/08/15 15:46:08
Use r"".
clee
2011/08/15 18:07:09
Done.
|
+ test_ok = re.compile( |
+ ansi_regex + "\[\s+OK\s+\] " + ansi_regex + test_name_regex) |
test_fail = re.compile( |
- ansi_code_regex + "\[\s+FAILED\s+\] " + ansi_code_regex + |
- test_name_regex) |
+ ansi_regex + "\[\s+FAILED\s+\] " + ansi_regex + test_name_regex) |
test_timeout = re.compile( |
"Test timeout \([0-9]+ ms\) exceeded for " + test_name_regex) |
@@ -198,12 +223,9 @@ class ShardingSupervisor(object): |
for i in range(self.num_shards): |
counter.put(i) |
- # Disable stdout buffering to read shard output one character at a time. |
- # This allows for shard crashes that do not end with a "\n". |
- sys.stdout = os.fdopen(sys.stdout.fileno(), "w", 0) |
- |
for i in range(self.num_runs): |
- worker = ShardRunner(self, counter, test_fail, test_timeout) |
+ worker = ShardRunner( |
+ self, counter, test_start, test_ok, test_fail, test_timeout) |
worker.start() |
workers.append(worker) |
if self.reorder: |
@@ -212,10 +234,7 @@ class ShardingSupervisor(object): |
for worker in workers: |
worker.join() |
- # Re-enable stdout buffering. |
- sys.stdout = sys.__stdout__ |
- |
- return self.PrintSummary() |
+ return self.PrintSummary(self.failure_log) |
def LogLineFailure(self, line): |
"""Saves a line in the failure log to be printed at the end. |
@@ -251,7 +270,7 @@ class ShardingSupervisor(object): |
def ShardIndexCompleted(self, index): |
self.shard_output[index].put(self.SHARD_COMPLETED) |
- def PrintSummary(self): |
+ def PrintSummary(self, failed_tests): |
"""Prints a summary of the test results. |
If any shards had failing tests, the list is sorted and printed. Then all |
@@ -264,25 +283,26 @@ class ShardingSupervisor(object): |
num_failed = len(self.failed_shards) |
if num_failed > 0: |
self.failed_shards.sort() |
- if self.color: |
- sys.stderr.write("\x1b[1;5;31m") |
- sys.stderr.write("SHARDS THAT FAILED: %s\n" % str(self.failed_shards)) |
+ self.WriteText(sys.stderr, |
+ "FAILED SHARDS: %s\n" % str(self.failed_shards), |
+ "\x1b[1;5;31m") |
else: |
- if self.color: |
- sys.stderr.write("\x1b[1;5;32m") |
- sys.stderr.write("ALL SHARDS PASSED!\n") |
- if self.failure_log: |
- if self.color: |
- sys.stderr.write("\x1b[1;5;31m") |
- sys.stderr.write("TESTS THAT DID NOT PASS:\n") |
- if self.color: |
- sys.stderr.write("\x1b[m") |
- for line in self.failure_log: |
+ self.WriteText(sys.stderr, "ALL SHARDS PASSED!\n", "\x1b[1;5;32m") |
+ if failed_tests: |
+ self.WriteText(sys.stderr, "FAILED TESTS:\n", "\x1b[1;5;31m") |
+ for line in failed_tests: |
sys.stderr.write(line) |
if self.color: |
sys.stderr.write("\x1b[m") |
return num_failed |
+ def WriteText(self, pipe, text, ansi): |
+ if self.color: |
+ pipe.write(ansi) |
+ pipe.write(text) |
+ if self.color: |
+ pipe.write("\x1b[m") |
+ |
def main(): |
parser = optparse.OptionParser(usage=SS_USAGE) |