[autotest] add an ignore_deps parameter to Suite constructor
This CL adds a ignore_deps flag to the Suite constructor. When the flag
is passed in as true, jobs will be scheduled without using any of the
dependencies specified in their control file's DEPENCENCY attribute.
This flag is useful in test_that, to avoid the need to add label objects
and assign labels to the (one-and-only) host that will exist in its
sqlite in-memory afe database.
BUG=chromium:236471
TEST=Modified suite unit tests to be sensitive to dependencies.
Added a test that uses the ignore_deps flag. All existing and new tests
pass.
Change-Id: I4a0de64fcc9e197f357106279fd8da35ab8ba90d
Reviewed-on: https://gerrit.chromium.org/gerrit/55855
Commit-Queue: Aviv Keshet <akeshet@chromium.org>
Reviewed-by: Aviv Keshet <akeshet@chromium.org>
Tested-by: Aviv Keshet <akeshet@chromium.org>
diff --git a/server/cros/dynamic_suite/fakes.py b/server/cros/dynamic_suite/fakes.py
index fe7d505..cd18645 100644
--- a/server/cros/dynamic_suite/fakes.py
+++ b/server/cros/dynamic_suite/fakes.py
@@ -8,7 +8,8 @@
class FakeControlData(object):
"""A fake parsed control file data structure."""
- def __init__(self, suite, data, time='LONG', expr=False):
+ def __init__(self, suite, data, time='LONG', expr=False,
+ dependencies=None):
self.string = 'text-' + data
self.name = 'name-' + data
self.path = None # Will be set during 'parsing'.
@@ -16,7 +17,9 @@
self.suite = suite
self.test_type = 'Client'
self.experimental = expr
- self.dependencies = []
+ if not dependencies:
+ dependencies=[]
+ self.dependencies = dependencies
self.time = time
self.retries = 0
diff --git a/server/cros/dynamic_suite/suite.py b/server/cros/dynamic_suite/suite.py
index fbf5a1b..dcfd569 100644
--- a/server/cros/dynamic_suite/suite.py
+++ b/server/cros/dynamic_suite/suite.py
@@ -110,7 +110,8 @@
tko=None, pool=None, results_dir=None,
max_runtime_mins=24*60,
version_prefix=constants.VERSION_PREFIX,
- file_bugs=False):
+ file_bugs=False, suite_job_id=None,
+ ignore_deps=False):
"""
Create a Suite using a predicate based on the SUITE control file var.
@@ -138,6 +139,11 @@
test.
@param file_bugs: True if we should file bugs on test failures for
this suite run.
+ @param suite_job_id: Job id that will act as parent id to all sub jobs.
+ Default: None
+ @param ignore_deps: True if jobs should ignore the DEPENDENCIES
+ attribute and skip applying of dependency labels.
+ (Default:False)
@return a Suite instance.
"""
if cf_getter is None:
@@ -145,7 +151,8 @@
return Suite(Suite.name_in_tag_predicate(name),
name, build, cf_getter, afe, tko, pool, results_dir,
- max_runtime_mins, version_prefix, file_bugs)
+ max_runtime_mins, version_prefix, file_bugs, suite_job_id,
+ ignore_deps)
@staticmethod
@@ -155,7 +162,8 @@
max_runtime_mins=24*60,
version_prefix=constants.VERSION_PREFIX,
file_bugs=False,
- suite_job_id=None):
+ suite_job_id=None,
+ ignore_deps=False):
"""
Create a Suite using a predicate based on the SUITE control file var.
@@ -186,6 +194,9 @@
this suite run.
@param suite_job_id: Job id that will act as parent id to all sub jobs.
Default: None
+ @param ignore_deps: True if jobs should ignore the DEPENDENCIES
+ attribute and skip applying of dependency labels.
+ (Default:False)
@return a Suite instance.
"""
if cf_getter is None:
@@ -205,7 +216,7 @@
def __init__(self, predicate, 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, suite_job_id=None):
+ file_bugs=False, suite_job_id=None, ignore_deps=False):
"""
Constructor
@@ -227,6 +238,9 @@
associated with the build
@param suite_job_id: Job id that will act as parent id to all sub jobs.
Default: None
+ @param ignore_deps: True if jobs should ignore the DEPENDENCIES
+ attribute and skip applying of dependency labels.
+ (Default:False)
"""
self._predicate = predicate
self._tag = tag
@@ -248,6 +262,7 @@
self._version_prefix = version_prefix
self._file_bugs = file_bugs
self._suite_job_id = suite_job_id
+ self._ignore_deps = ignore_deps
@property
@@ -281,7 +296,10 @@
test_name is used to preserve the higher level TEST_NAME
name of the job.
"""
- job_deps = list(test.dependencies)
+ if self._ignore_deps:
+ job_deps = []
+ else:
+ job_deps = list(test.dependencies)
if self._pool:
meta_hosts = self._pool
cros_label = self._version_prefix + self._build
diff --git a/server/cros/dynamic_suite/suite_unittest.py b/server/cros/dynamic_suite/suite_unittest.py
index 4f358d1..963d432 100644
--- a/server/cros/dynamic_suite/suite_unittest.py
+++ b/server/cros/dynamic_suite/suite_unittest.py
@@ -48,16 +48,17 @@
self.getter = self.mox.CreateMock(control_file_getter.ControlFileGetter)
self.devserver = dev_server.ImageServer(self._DEVSERVER_HOST)
- self.files = {'one': FakeControlData(self._TAG, 'data_one',
- 'FAST', expr=True),
- 'two': FakeControlData(self._TAG, 'data_two',
- 'SHORT'),
+ self.files = {'one': FakeControlData(self._TAG, 'data_one', 'FAST',
+ expr=True),
+ 'two': FakeControlData(self._TAG, 'data_two', 'SHORT',
+ dependencies=['feta']),
'three': FakeControlData(self._TAG, 'data_three',
'MEDIUM'),
- 'four': FakeControlData('other', 'data_four',
- 'LONG'),
- 'five': FakeControlData(self._TAG, 'data_five',
- 'LONG'),
+ 'four': FakeControlData('other', 'data_four', 'LONG',
+ dependencies=['arugula']),
+ 'five': FakeControlData(self._TAG, 'data_five', 'LONG',
+ dependencies=['arugula',
+ 'caligula']),
'six': FakeControlData(self._TAG, 'data_six',
'LENGTHY')}
@@ -174,13 +175,14 @@
def expect_job_scheduling(self, recorder, add_experimental,
- tests_to_skip=[]):
+ tests_to_skip=[], ignore_deps=False):
"""Expect jobs to be scheduled for 'tests' in |self.files|.
@param add_experimental: expect jobs for experimental tests as well.
@param recorder: object with a record_entry to be used to record test
results.
@param tests_to_skip: [list, of, test, names] that we expect to skip.
+ @param ignore_deps: If true, ignore tests' dependencies.
"""
recorder.record_entry(
StatusContains.CreateFromStrings('INFO', 'Start %s' % self._TAG))
@@ -189,13 +191,17 @@
continue
if test.name in tests_to_skip:
continue
+ if ignore_deps:
+ dependencies = []
+ else:
+ dependencies = test.dependencies
self.afe.create_job(
control_file=test.text,
name=mox.And(mox.StrContains(self._BUILD),
mox.StrContains(test.name)),
control_type=mox.IgnoreArg(),
meta_hosts=[constants.VERSION_PREFIX + self._BUILD],
- dependencies=[],
+ dependencies=dependencies,
keyvals={'build': self._BUILD, 'suite': self._TAG},
max_runtime_mins=24*60,
parent_job_id=None,
@@ -235,6 +241,21 @@
suite.schedule(recorder.record_entry, add_experimental=False)
+ def testScheduleStableTestsIgnoreDeps(self):
+ """Should schedule only stable tests with the AFE."""
+ self.mock_control_file_parsing()
+ recorder = self.mox.CreateMock(base_job.base_job)
+ self.expect_job_scheduling(recorder, add_experimental=False,
+ ignore_deps=True)
+
+ self.mox.ReplayAll()
+ suite = Suite.create_from_name(self._TAG, self._BUILD,
+ self.devserver,
+ afe=self.afe, tko=self.tko,
+ ignore_deps=True)
+ suite.schedule(recorder.record_entry, add_experimental=False)
+
+
def _createSuiteWithMockedTestsAndControlFiles(self, file_bugs=False):
"""Create a Suite, using mocked tests and control file contents.