[autotest] make Suite constructor accept list of predicates
This CL refactors some of the test-hunting predicate logic, to make it
easier (in a future CL) for test_that kicked off at a user's desk to
schedule ad-hoc suites, either in the lab or at their desk.
Prior to this CL, the `predicate` argument to Suite's constructor was a
single callable that mapped ControlData objects to Booleans (True =
include in suite, False = exclude from suite). After this CL, Suite's
constructor will also accept a list of callables for the `predicate`
argument. If a list is supplied the predicates in the list will be
logically ANDed to create the predicate used to hunt for tests.
This CL also adds a new predicate factory, for predicates that matche
Control Files based on test name.
BUG=chromium:246750
TEST=relevant unit tests pass; kicked off a suite in local autotest and
it ran
Change-Id: Idb48669f9da44cff9efdbe57ac08537a27747433
Reviewed-on: https://gerrit.chromium.org/gerrit/57552
Tested-by: Aviv Keshet <akeshet@chromium.org>
Reviewed-by: Alex Miller <milleral@chromium.org>
Commit-Queue: Aviv Keshet <akeshet@chromium.org>
diff --git a/server/cros/dynamic_suite/suite.py b/server/cros/dynamic_suite/suite.py
index 0a23d22..ab55684 100644
--- a/server/cros/dynamic_suite/suite.py
+++ b/server/cros/dynamic_suite/suite.py
@@ -82,6 +82,35 @@
@staticmethod
+ def not_in_blacklist_predicate(blacklist):
+ """Returns predicate that takes a control file and looks for its
+ path to not be in given blacklist.
+
+ @param blacklist: A list of strings both paths on control_files that
+ should be blacklisted.
+
+ @return a callable that takes a ControlData and looks for it to be
+ absent from blacklist.
+ """
+ return lambda t: hasattr(t, 'path') and \
+ not any(b.endswith(t.path) for b in blacklist)
+
+
+ @staticmethod
+ def test_name_equals_predicate(test_name):
+ """Returns predicate that matched based on a test's name.
+
+ Builds a predicate that takes in a parsed control file (a ControlData)
+ and returns True if the test name is equal to |test_name|.
+
+ @param test_name: the test name to base the predicate on.
+ @return a callable that takes a ControlData and looks for |test_name|
+ in that ControlData's name.
+ """
+ return lambda t: hasattr(t, 'name') and test_name == t.name
+
+
+ @staticmethod
def list_all_suites(build, devserver, cf_getter=None):
"""
Parses all ControlData objects with a SUITE tag and extracts all
@@ -127,7 +156,7 @@
if cf_getter is None:
cf_getter = Suite.create_ds_getter(build, devserver)
- return Suite(Suite.name_in_tag_predicate(name),
+ return Suite([Suite.name_in_tag_predicate(name)],
name, build, cf_getter, **dargs)
@@ -155,17 +184,13 @@
if cf_getter is None:
cf_getter = Suite.create_ds_getter(build, devserver)
- def in_tag_not_in_blacklist_predicate(test):
- #pylint: disable-msg=C0111
- return (Suite.name_in_tag_predicate(name)(test) and
- hasattr(test, 'path') and
- True not in [b.endswith(test.path) for b in blacklist])
+ predicates = [Suite.name_in_tag_predicate(name),
+ Suite.not_in_blacklist_predicate(blacklist)]
- return Suite(in_tag_not_in_blacklist_predicate,
- name, build, cf_getter, **dargs)
+ return Suite(predicates, name, build, cf_getter, **dargs)
- def __init__(self, predicate, tag, build, cf_getter, afe=None, tko=None,
+ def __init__(self, predicates, tag, build, cf_getter, afe=None, tko=None,
pool=None, results_dir=None, max_runtime_mins=24*60,
version_prefix=constants.VERSION_PREFIX,
file_bugs=False, file_experimental_bugs=False,
@@ -173,9 +198,10 @@
"""
Constructor
- @param predicate: a function that should return True when run over a
- ControlData representation of a control file that should be in
- this Suite.
+ @param predicates: A list of callables that accept ControlData
+ representations of control files. A test will be
+ included in suite is all callables in this list
+ return True on the given control file.
@param tag: a string with which to tag jobs run in this suite.
@param build: the build on which we're running this suite.
@param cf_getter: a control_file_getter.ControlFileGetter
@@ -195,7 +221,11 @@
attribute and skip applying of dependency labels.
(Default:False)
"""
- self._predicate = predicate
+ def combined_predicate(test):
+ #pylint: disable-msg=C0111
+ return all((f(test) for f in predicates))
+ self._predicate = combined_predicate
+
self._tag = tag
self._build = build
self._cf_getter = cf_getter