Stop metajob application of undefined attributes

Previously, metajobs set defaults for boolean attributes that were not
defined, and copied to them to matched jobs.  This could result in a
metajob that did not define a voting attribute unintentially
overriding a matched job with the default voting value (True).  This
change ensures that metajobs set values only for explicitly supplied
boolean attributes.

Change-Id: I99dc3a58c63946ddb54849b1629101b062159a69
Closes-Bug: #2000166
This commit is contained in:
Maru Newby
2015-02-17 17:54:45 +00:00
parent 848b6aca93
commit 79427a4020
2 changed files with 37 additions and 6 deletions

View File

@@ -43,3 +43,22 @@ class TestJob(BaseTestCase):
job = model.Job('job')
job.copy(self.job)
self.assertTrue(job.skip_if_matcher)
def _assert_job_booleans_are_not_none(self, job):
self.assertIsNotNone(job.voting)
self.assertIsNotNone(job.hold_following_changes)
def test_job_sets_defaults_for_boolean_attributes(self):
job = model.Job('job')
self._assert_job_booleans_are_not_none(job)
def test_metajob_does_not_set_defaults_for_boolean_attributes(self):
job = model.Job('^job')
self.assertIsNone(job.voting)
self.assertIsNone(job.hold_following_changes)
def test_metajob_copy_does_not_set_undefined_boolean_attributes(self):
job = model.Job('job')
metajob = model.Job('^job')
job.copy(metajob)
self._assert_job_booleans_are_not_none(job)

View File

@@ -452,8 +452,14 @@ class Job(object):
self.failure_pattern = None
self.success_pattern = None
self.parameter_function = None
self.hold_following_changes = False
self.voting = True
# A metajob should only supply values for attributes that have
# been explicitly provided, so avoid setting boolean defaults.
if self.is_metajob:
self.hold_following_changes = None
self.voting = None
else:
self.hold_following_changes = False
self.voting = True
self.branches = []
self._branches = []
self.files = []
@@ -467,6 +473,10 @@ class Job(object):
def __repr__(self):
return '<Job %s>' % (self.name)
@property
def is_metajob(self):
return self.name.startswith('^')
def copy(self, other):
if other.failure_message:
self.failure_message = other.failure_message
@@ -488,8 +498,11 @@ class Job(object):
self.skip_if_matcher = other.skip_if_matcher.copy()
if other.swift:
self.swift.update(other.swift)
self.hold_following_changes = other.hold_following_changes
self.voting = other.voting
# Only non-None values should be copied for boolean attributes.
if other.hold_following_changes is not None:
self.hold_following_changes = other.hold_following_changes
if other.voting is not None:
self.voting = other.voting
def changeMatches(self, change):
matches_branch = False
@@ -1269,8 +1282,7 @@ class Layout(object):
if name in self.jobs:
return self.jobs[name]
job = Job(name)
if name.startswith('^'):
# This is a meta-job
if job.is_metajob:
regex = re.compile(name)
self.metajobs.append((regex, job))
else: