Commit fbe973ff authored by machenbach's avatar machenbach Committed by Commit bot

[test] Refactoring - Use subject/observer pattern for progress indicators.

This should prevent bugs caused by missing super calls in
overridden methods. The assumption is that methods of
different indicators are independent.

Review URL: https://codereview.chromium.org/1171943002

Cr-Commit-Position: refs/heads/master@{#28866}
parent ae06bdde
......@@ -610,14 +610,14 @@ def Execute(arch, mode, args, options, suites, workspace):
# Run the tests, either locally or distributed on the network.
start_time = time.time()
progress_indicator = progress.PROGRESS_INDICATORS[options.progress]()
progress_indicator = progress.IndicatorNotifier()
progress_indicator.Register(progress.PROGRESS_INDICATORS[options.progress]())
if options.junitout:
progress_indicator = progress.JUnitTestProgressIndicator(
progress_indicator, options.junitout, options.junittestsuite)
progress_indicator.Register(progress.JUnitTestProgressIndicator(
options.junitout, options.junittestsuite))
if options.json_test_results:
progress_indicator = progress.JsonTestProgressIndicator(
progress_indicator, options.json_test_results, arch,
MODES[mode]["execution_mode"])
progress_indicator.Register(progress.JsonTestProgressIndicator(
options.json_test_results, arch, MODES[mode]["execution_mode"]))
run_networked = not options.no_network
if not run_networked:
......
......@@ -82,7 +82,7 @@ class Runner(object):
t.id = self.total
self.total += 1
self.indicator = progress_indicator
progress_indicator.runner = self
progress_indicator.SetRunner(self)
self.context = context
self.succeeded = 0
self.remaining = self.total
......
......@@ -26,6 +26,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from functools import wraps
import json
import os
import sys
......@@ -54,6 +55,9 @@ class ProgressIndicator(object):
def __init__(self):
self.runner = None
def SetRunner(self, runner):
self.runner = runner
def Starting(self):
pass
......@@ -80,6 +84,30 @@ class ProgressIndicator(object):
}
class IndicatorNotifier(object):
"""Holds a list of progress indicators and notifies them all on events."""
def __init__(self):
self.indicators = []
def Register(self, indicator):
self.indicators.append(indicator)
# Forge all generic event-dispatching methods in IndicatorNotifier, which are
# part of the ProgressIndicator interface.
for func_name in ProgressIndicator.__dict__:
func = getattr(ProgressIndicator, func_name)
if callable(func) and not func.__name__.startswith('_'):
def wrap_functor(f):
@wraps(f)
def functor(self, *args, **kwargs):
"""Generic event dispatcher."""
for indicator in self.indicators:
getattr(indicator, f.__name__)(*args, **kwargs)
return functor
setattr(IndicatorNotifier, func_name, wrap_functor(func))
class SimpleProgressIndicator(ProgressIndicator):
"""Abstract base class for {Verbose,Dots}ProgressIndicator"""
......@@ -251,29 +279,19 @@ class MonochromeProgressIndicator(CompactProgressIndicator):
class JUnitTestProgressIndicator(ProgressIndicator):
def __init__(self, progress_indicator, junitout, junittestsuite):
self.progress_indicator = progress_indicator
def __init__(self, junitout, junittestsuite):
self.outputter = junit_output.JUnitTestOutput(junittestsuite)
if junitout:
self.outfile = open(junitout, "w")
else:
self.outfile = sys.stdout
def Starting(self):
self.progress_indicator.runner = self.runner
self.progress_indicator.Starting()
def Done(self):
self.progress_indicator.Done()
self.outputter.FinishAndWrite(self.outfile)
if self.outfile != sys.stdout:
self.outfile.close()
def AboutToRun(self, test):
self.progress_indicator.AboutToRun(test)
def HasRun(self, test, has_unexpected_output):
self.progress_indicator.HasRun(test, has_unexpected_output)
fail_text = ""
if has_unexpected_output:
stdout = test.output.stdout.strip()
......@@ -292,25 +310,17 @@ class JUnitTestProgressIndicator(ProgressIndicator):
test.duration,
fail_text)
def Heartbeat(self):
self.progress_indicator.Heartbeat()
class JsonTestProgressIndicator(ProgressIndicator):
def __init__(self, progress_indicator, json_test_results, arch, mode):
self.progress_indicator = progress_indicator
def __init__(self, json_test_results, arch, mode):
self.json_test_results = json_test_results
self.arch = arch
self.mode = mode
self.results = []
self.tests = []
def Starting(self):
self.progress_indicator.runner = self.runner
self.progress_indicator.Starting()
def Done(self):
self.progress_indicator.Done()
complete_results = []
if os.path.exists(self.json_test_results):
with open(self.json_test_results, "r") as f:
......@@ -340,11 +350,7 @@ class JsonTestProgressIndicator(ProgressIndicator):
with open(self.json_test_results, "w") as f:
f.write(json.dumps(complete_results))
def AboutToRun(self, test):
self.progress_indicator.AboutToRun(test)
def HasRun(self, test, has_unexpected_output):
self.progress_indicator.HasRun(test, has_unexpected_output)
# Buffer all tests for sorting the durations in the end.
self.tests.append(test)
if not has_unexpected_output:
......@@ -366,9 +372,6 @@ class JsonTestProgressIndicator(ProgressIndicator):
"duration": test.duration,
})
def Heartbeat(self):
self.progress_indicator.Heartbeat()
PROGRESS_INDICATORS = {
'verbose': VerboseProgressIndicator,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment