Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(720)

Unified Diff: scripts/slave/recipe_modules/test_utils/api.py

Issue 313693003: Swarming: conditionally run tests on swarming in chromium_trybot recipe. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: scripts/slave/recipe_modules/test_utils/api.py
diff --git a/scripts/slave/recipe_modules/test_utils/api.py b/scripts/slave/recipe_modules/test_utils/api.py
index a91b801feb820c1bbfeac33cb411ff90788e3e52..de876ff8bfcbedfd401b947bcd67e4bbf8cb5c71 100644
--- a/scripts/slave/recipe_modules/test_utils/api.py
+++ b/scripts/slave/recipe_modules/test_utils/api.py
@@ -40,6 +40,13 @@ class TestUtilsApi(recipe_api.RecipeApi):
Base class for tests that can be retried after deapplying a previously
applied patch.
"""
+ # If True, the test supports asynchronous execution. In that case 'trigger'
+ # and 'collect' will be used instead of 'run'. 'trigger' produces a step
+ # that asynchronously launches the test (just starts the test and
+ # immediately returns control back to the recipe), and 'collect' produces
+ # a step that blocks until the test is finished. The recipe can execute any
+ # other steps in between. This mode is used by tests running on Swarming.
+ async = False
@property
def name(self): # pragma: no cover
@@ -50,6 +57,14 @@ class TestUtilsApi(recipe_api.RecipeApi):
"""Run the test. suffix is 'with patch' or 'without patch'."""
raise NotImplementedError()
+ def trigger(self, suffix): # pragma: no cover
+ """Launch the test asynchronously, used if self.async == True."""
+ raise NotImplementedError()
+
+ def collect(self, suffix): # pragma: no cover
+ """Wait for triggered test to finish, used if self.async == True."""
+ raise NotImplementedError()
+
def has_valid_results(self, suffix): # pragma: no cover
"""
Returns True if results (failures) are valid.
@@ -79,6 +94,9 @@ class TestUtilsApi(recipe_api.RecipeApi):
deapply_patch_fn - function that takes a list of failing tests
and undoes any effect of the previously applied patch
"""
+ # Convert iterable to list, since it is enumerated multiple times.
+ tests = list(tests)
+
if self.m.step_history.failed:
yield self.m.python.inline(
'Aborting due to failed build state.',
@@ -86,7 +104,24 @@ class TestUtilsApi(recipe_api.RecipeApi):
always_run=True, abort_on_failure=True)
return # won't actually hit this, but be explicit
- yield (t.run('with patch') for t in tests)
+ def run(prefix, tests):
+ """Runs synchronous and asynchronous tests (at the same time).
+
+ Asynchronous tests are launched first (just launched, not being blocked
+ on). While they are running, the recipe blocks on synchronous tests
+ (sequentially, one by one). And then finally waits for all asynchronous
+ tests to finish. Effectively asynchronous tests are running in parallel
+ with each other and with synchronous tests.
+ """
+ # Trigger all async tests first, so that they are running in parallel
+ # with synchronous tests.
+ yield (t.trigger(prefix) for t in tests if t.async)
+ # Now block on all synchronous tests.
+ yield (t.run(prefix) for t in tests if not t.async)
+ # And finally wait for all pending asynchronous tests to complete.
+ yield (t.collect(prefix) for t in tests if t.async)
+
+ yield run('with patch', tests)
failing_tests = []
for t in tests:
@@ -106,7 +141,7 @@ class TestUtilsApi(recipe_api.RecipeApi):
yield deapply_patch_fn(failing_tests)
- yield (t.run('without patch') for t in failing_tests)
+ yield run('without patch', failing_tests)
yield (self._summarize_retried_test(t) for t in failing_tests)
def _summarize_retried_test(self, test):

Powered by Google App Engine
This is Rietveld 408576698