blob: 7bbb979c17c9ea3950a259c8ffa2f7a51bae9a44 [file] [log] [blame]
# Copyright 2013 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Test the cbuildbot_run module."""
import pickle
import time
from unittest import mock
from chromite.cbuildbot import cbuildbot_run
from chromite.lib import config_lib
from chromite.lib import config_lib_unittest
from chromite.lib import cros_test_lib
from chromite.lib import parallel
DEFAULT_ARCHIVE_GS_PATH = "bogus_bucket/TheArchiveBase"
DEFAULT_ARCHIVE_BASE = "gs://%s" % DEFAULT_ARCHIVE_GS_PATH
DEFAULT_BUILDROOT = "/tmp/foo/bar/buildroot"
DEFAULT_BUILDNUMBER = 12345
DEFAULT_BRANCH = "TheBranch"
DEFAULT_CHROME_BRANCH = "TheChromeBranch"
DEFAULT_VERSION_STRING = "TheVersionString"
DEFAULT_BOARD = "TheBoard"
DEFAULT_BOT_NAME = "TheCoolBot"
# pylint: disable=protected-access
DEFAULT_OPTIONS = cros_test_lib.EasyAttr(
archive_base=DEFAULT_ARCHIVE_BASE,
buildroot=DEFAULT_BUILDROOT,
buildnumber=DEFAULT_BUILDNUMBER,
buildbot=True,
branch=DEFAULT_BRANCH,
remote_trybot=False,
debug=False,
postsync_patch=True,
)
DEFAULT_CONFIG = config_lib.BuildConfig(
name=DEFAULT_BOT_NAME,
master=True,
boards=[DEFAULT_BOARD],
postsync_patch=True,
child_configs=[
config_lib.BuildConfig(name="foo", postsync_patch=False, boards=[]),
config_lib.BuildConfig(name="bar", postsync_patch=False, boards=[]),
],
)
DEFAULT_VERSION = "6543.2.1"
def _ExtendDefaultOptions(**kwargs):
"""Extend DEFAULT_OPTIONS with keys/values in kwargs."""
options_kwargs = DEFAULT_OPTIONS.copy()
options_kwargs.update(kwargs)
return cros_test_lib.EasyAttr(**options_kwargs)
def _ExtendDefaultConfig(**kwargs):
"""Extend DEFAULT_CONFIG with keys/values in kwargs."""
config_kwargs = DEFAULT_CONFIG.copy()
config_kwargs.update(kwargs)
return config_lib.BuildConfig(**config_kwargs)
class ExceptionsTest(cros_test_lib.TestCase):
"""Test that the exceptions in the module are sane."""
def _TestException(self, err, expected_startswith):
"""Test that str and pickle behavior of |err| are as expected."""
err2 = pickle.loads(pickle.dumps(err, pickle.HIGHEST_PROTOCOL))
self.assertTrue(str(err).startswith(expected_startswith))
self.assertEqual(str(err), str(err2))
def testParallelAttributeError(self):
"""Test ParallelAttributeError message and pickle behavior."""
err1 = cbuildbot_run.ParallelAttributeError("SomeAttr")
self._TestException(err1, "No such parallel run attribute")
err2 = cbuildbot_run.ParallelAttributeError(
"SomeAttr", "SomeBoard", "SomeTarget"
)
self._TestException(
err2, "No such board-specific parallel run attribute"
)
def testAttrSepCountError(self):
"""Test AttrSepCountError message and pickle behavior."""
err1 = cbuildbot_run.AttrSepCountError("SomeAttr")
self._TestException(err1, "Attribute name has an unexpected number")
def testAttrNotPickleableError(self):
"""Test AttrNotPickleableError message and pickle behavior."""
err1 = cbuildbot_run.AttrNotPickleableError("SomeAttr", "SomeValue")
self._TestException(err1, 'Run attribute "SomeAttr" value cannot')
# TODO(mtennant): Turn this into a PartialMock.
class _BuilderRunTestCase(cros_test_lib.MockTestCase):
"""Provide methods for creating BuilderRun or ChildBuilderRun."""
def setUp(self):
self._manager = parallel.Manager()
# Mimic entering a 'with' statement.
# Pylint-1.9 has a false positive on this for some reason.
self._manager.__enter__() # pylint: disable=no-value-for-parameter
def tearDown(self):
# Mimic exiting a 'with' statement.
self._manager.__exit__(None, None, None)
def _NewRunAttributes(self):
return cbuildbot_run.RunAttributes(self._manager)
def _NewBuilderRun(self, options=None, config=None):
"""Create a BuilderRun objection from options and config values.
Args:
options: Specify options or default to DEFAULT_OPTIONS.
config: Specify build config or default to DEFAULT_CONFIG.
Returns:
BuilderRun object.
"""
options = options or DEFAULT_OPTIONS
config = config or DEFAULT_CONFIG
site_config = config_lib_unittest.MockSiteConfig()
site_config[config.name] = config
return cbuildbot_run.BuilderRun(
options, site_config, config, self._manager
)
def _NewChildBuilderRun(self, child_index, options=None, config=None):
"""Create a ChildBuilderRun objection from options and config values.
Args:
child_index: Index of child config to use within config.
options: Specify options or default to DEFAULT_OPTIONS.
config: Specify build config or default to DEFAULT_CONFIG.
Returns:
ChildBuilderRun object.
"""
run = self._NewBuilderRun(options, config)
return cbuildbot_run.ChildBuilderRun(run, child_index)
class BuilderRunPickleTest(_BuilderRunTestCase):
"""Make sure BuilderRun objects can be pickled."""
def setUp(self):
self.real_config = config_lib.GetConfig()["test-ap-group"]
self.PatchObject(
cbuildbot_run._BuilderRunBase,
"GetVersion",
return_value=DEFAULT_VERSION,
)
def _TestPickle(self, run1):
self.assertEqual(DEFAULT_VERSION, run1.GetVersion())
run1.attrs.release_tag = "TheReleaseTag"
# Accessing a method on BuilderRun has special behavior, so access and
# use one before pickling.
patch_after_sync = run1.ShouldPatchAfterSync()
# Access the archive object before pickling, too.
upload_url = run1.GetArchive().upload_url
# Pickle and unpickle run1 into run2.
run2 = pickle.loads(pickle.dumps(run1, pickle.HIGHEST_PROTOCOL))
self.assertEqual(run1.buildnumber, run2.buildnumber)
self.assertEqual(run1.config.boards, run2.config.boards)
self.assertEqual(run1.options.branch, run2.options.branch)
self.assertEqual(run1.attrs.release_tag, run2.attrs.release_tag)
self.assertRaises(
AttributeError, getattr, run1.attrs, "manifest_manager"
)
self.assertRaises(
AttributeError, getattr, run2.attrs, "manifest_manager"
)
self.assertEqual(patch_after_sync, run2.ShouldPatchAfterSync())
self.assertEqual(upload_url, run2.GetArchive().upload_url)
# The attrs objects should be identical.
self.assertIs(run1.attrs, run2.attrs)
# And the run objects themselves are different.
self.assertIsNot(run1, run2)
def testPickleBuilderRun(self):
self._TestPickle(self._NewBuilderRun(config=self.real_config))
def testPickleChildBuilderRun(self):
self._TestPickle(self._NewChildBuilderRun(0, config=self.real_config))
class BuilderRunTest(_BuilderRunTestCase):
"""Test the BuilderRun class."""
def testInit(self):
with mock.patch.object(
cbuildbot_run._BuilderRunBase, "GetVersion"
) as m:
m.return_value = DEFAULT_VERSION
run = self._NewBuilderRun()
self.assertEqual(DEFAULT_BUILDROOT, run.buildroot)
self.assertEqual(DEFAULT_BUILDNUMBER, run.buildnumber)
self.assertEqual(DEFAULT_BRANCH, run.manifest_branch)
self.assertEqual(DEFAULT_OPTIONS, run.options)
self.assertEqual(DEFAULT_CONFIG, run.config)
self.assertIsInstance(run.attrs, cbuildbot_run.RunAttributes)
self.assertIsInstance(
run.GetArchive(), cbuildbot_run.archive_lib.Archive
)
# Make sure methods behave normally, since BuilderRun messes with them.
meth1 = run.GetVersionInfo
meth2 = run.GetVersionInfo
self.assertEqual(meth1.__name__, meth2.__name__)
# We actually do not support identity and equality checks right now.
self.assertNotEqual(meth1, meth2)
self.assertIsNot(meth1, meth2)
def testOptions(self):
options = _ExtendDefaultOptions(foo=True, bar=10)
run = self._NewBuilderRun(options=options)
self.assertEqual(True, run.options.foo)
self.assertEqual(10, run.options.__getattr__("bar"))
self.assertRaises(AttributeError, run.options.__getattr__, "baz")
def testConfig(self):
config = _ExtendDefaultConfig(foo=True, bar=10)
run = self._NewBuilderRun(config=config)
self.assertEqual(True, run.config.foo)
self.assertEqual(10, run.config.__getattr__("bar"))
self.assertRaises(AttributeError, run.config.__getattr__, "baz")
def testAttrs(self):
run = self._NewBuilderRun()
# manifest_manager is a valid run attribute. It gives Attribute error
# if accessed before being set, but thereafter works fine.
self.assertRaises(
AttributeError, run.attrs.__getattribute__, "manifest_manager"
)
run.attrs.manifest_manager = "foo"
self.assertEqual("foo", run.attrs.manifest_manager)
self.assertEqual("foo", run.attrs.__getattribute__("manifest_manager"))
# foobar is not a valid run attribute. It gives AttributeError when
# accessed or changed.
self.assertRaises(AttributeError, run.attrs.__getattribute__, "foobar")
self.assertRaises(
AttributeError, run.attrs.__setattr__, "foobar", "foo"
)
def testArchive(self):
run = self._NewBuilderRun()
with mock.patch.object(
cbuildbot_run._BuilderRunBase, "GetVersion"
) as m:
m.return_value = DEFAULT_VERSION
archive = run.GetArchive()
# Check archive.archive_path.
expected = "%s/%s/%s/%s" % (
DEFAULT_BUILDROOT,
cbuildbot_run.archive_lib.Archive._BUILDBOT_ARCHIVE,
DEFAULT_BOT_NAME,
DEFAULT_VERSION,
)
self.assertEqual(expected, archive.archive_path)
# Check archive.upload_url.
expected = "%s/%s/%s" % (
DEFAULT_ARCHIVE_BASE,
DEFAULT_BOT_NAME,
DEFAULT_VERSION,
)
self.assertEqual(expected, archive.upload_url)
# Check archive.download_url.
expected = "%s%s/%s/%s" % (
cbuildbot_run.archive_lib.gs.PRIVATE_BASE_HTTPS_DOWNLOAD_URL,
DEFAULT_ARCHIVE_GS_PATH,
DEFAULT_BOT_NAME,
DEFAULT_VERSION,
)
self.assertEqual(expected, archive.download_url)
def testShouldUploadPrebuilts(self):
# Enabled
options = _ExtendDefaultOptions(prebuilts=True)
config = _ExtendDefaultConfig(prebuilts=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertTrue(run.ShouldUploadPrebuilts())
# Config disabled.
options = _ExtendDefaultOptions(prebuilts=True)
config = _ExtendDefaultConfig(prebuilts=False)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldUploadPrebuilts())
# Option disabled.
options = _ExtendDefaultOptions(prebuilts=False)
config = _ExtendDefaultConfig(prebuilts=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldUploadPrebuilts())
def testShouldPatchAfterSync(self):
# Enabled
options = _ExtendDefaultOptions(postsync_patch=True)
config = _ExtendDefaultConfig(postsync_patch=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertTrue(run.ShouldPatchAfterSync())
# Config disabled.
options = _ExtendDefaultOptions(postsync_patch=True)
config = _ExtendDefaultConfig(postsync_patch=False)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldPatchAfterSync())
# Option disabled.
options = _ExtendDefaultOptions(postsync_patch=False)
config = _ExtendDefaultConfig(postsync_patch=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldPatchAfterSync())
def testShouldReexecAfterSync(self):
# Normal Execution
options = _ExtendDefaultOptions(postsync_reexec=True, resume=False)
config = _ExtendDefaultConfig(postsync_reexec=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertTrue(run.ShouldReexecAfterSync())
# Normal after Rexec
options = _ExtendDefaultOptions(postsync_reexec=True, resume=True)
config = _ExtendDefaultConfig(postsync_reexec=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldReexecAfterSync())
# Turned off in config.
options = _ExtendDefaultOptions(postsync_reexec=True, resume=False)
config = _ExtendDefaultConfig(postsync_reexec=False)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldReexecAfterSync())
# Turned off on command line.
options = _ExtendDefaultOptions(postsync_reexec=False, resume=False)
config = _ExtendDefaultConfig(postsync_reexec=True)
run = self._NewBuilderRun(options=options, config=config)
self.assertFalse(run.ShouldReexecAfterSync())
def testInProduction(self):
run = self._NewBuilderRun()
self.assertFalse(run.InProduction())
def testInEmailReportingEnvironment(self):
run = self._NewBuilderRun()
self.assertFalse(run.InEmailReportingEnvironment())
class GetVersionTest(_BuilderRunTestCase):
"""Test the GetVersion and GetVersionInfo methods of BuilderRun class."""
# pylint: disable=protected-access
def testGetVersionInfoNotSet(self):
"""Verify we throw an error when the version hasn't been set."""
run = self._NewBuilderRun()
self.assertRaises(RuntimeError, run.GetVersionInfo)
def testGetVersionInfo(self):
"""Verify we return the right version info value."""
# Prepare a real BuilderRun object with a version_info tag.
run = self._NewBuilderRun()
verinfo = object()
run.attrs.version_info = verinfo
result = run.GetVersionInfo()
self.assertEqual(verinfo, result)
def _TestGetVersionReleaseTag(self, release_tag, cidb_id=None):
with mock.patch.object(
cbuildbot_run._BuilderRunBase, "GetVersionInfo"
) as m:
verinfo_mock = mock.Mock()
verinfo_mock.chrome_branch = DEFAULT_CHROME_BRANCH
verinfo_mock.VersionString = mock.Mock(return_value="VS")
m.return_value = verinfo_mock
# Prepare a real BuilderRun object with a release tag.
run = self._NewBuilderRun()
run.attrs.release_tag = release_tag
if cidb_id:
run.attrs.metadata.UpdateWithDict({"build_id": cidb_id})
# Run the test return the result.
result = run.GetVersion()
m.assert_called_once_with()
if release_tag is None:
verinfo_mock.VersionString.assert_called_once()
return result
def testGetVersionReleaseTag(self):
result = self._TestGetVersionReleaseTag("RT")
self.assertEqual("R%s-%s" % (DEFAULT_CHROME_BRANCH, "RT"), result)
def testGetVersionNoReleaseTag(self):
cidb_id = 12345678
result = self._TestGetVersionReleaseTag(None, cidb_id)
expected_result = "R%s-%s-b%s" % (DEFAULT_CHROME_BRANCH, "VS", cidb_id)
self.assertEqual(result, expected_result)
def testGetVersionNoReleaseTagNoCidb(self):
result = self._TestGetVersionReleaseTag(None)
expected_result = "R%s-%s-b%s" % (DEFAULT_CHROME_BRANCH, "VS", 0)
self.assertEqual(result, expected_result)
class ChildBuilderRunTest(_BuilderRunTestCase):
"""Test the ChildBuilderRun class"""
def testInit(self):
with mock.patch.object(
cbuildbot_run._BuilderRunBase, "GetVersion"
) as m:
m.return_value = DEFAULT_VERSION
crun = self._NewChildBuilderRun(0)
self.assertEqual(DEFAULT_BUILDROOT, crun.buildroot)
self.assertEqual(DEFAULT_BUILDNUMBER, crun.buildnumber)
self.assertEqual(DEFAULT_BRANCH, crun.manifest_branch)
self.assertEqual(DEFAULT_OPTIONS, crun.options)
self.assertEqual(DEFAULT_CONFIG.child_configs[0], crun.config)
self.assertEqual("foo", crun.config.name)
self.assertIsInstance(crun.attrs, cbuildbot_run.RunAttributes)
self.assertIsInstance(
crun.GetArchive(), cbuildbot_run.archive_lib.Archive
)
# Make sure methods behave normally, since BuilderRun messes with them.
meth1 = crun.GetVersionInfo
meth2 = crun.GetVersionInfo
self.assertEqual(meth1.__name__, meth2.__name__)
# We actually do not support identity and equality checks right now.
self.assertNotEqual(meth1, meth2)
self.assertIsNot(meth1, meth2)
class RunAttributesTest(_BuilderRunTestCase):
"""Test the RunAttributes class."""
BOARD = "SomeBoard"
TARGET = "SomeConfigName"
VALUE = "AnyValueWillDo"
# Any valid board-specific attribute will work here.
BATTR = "breakpad_symbols_generated"
def testRegisterBoardTarget(self):
"""Test behavior of attributes before and after registering board target."""
ra = self._NewRunAttributes()
with self.assertRaises(AssertionError):
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
ra.RegisterBoardAttrs(self.BOARD, self.TARGET)
self.assertFalse(
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
ra.SetBoardParallel(self.BATTR, "TheValue", self.BOARD, self.TARGET)
self.assertTrue(
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
def testSetGet(self):
"""Test simple set/get of regular and parallel run attributes."""
ra = self._NewRunAttributes()
value = "foobar"
# The __slots__ logic above confuses pylint.
# https://bitbucket.org/logilab/pylint/issue/380/
# pylint: disable=assigning-non-slot
# Set/Get a regular run attribute using direct access.
ra.release_tag = value
self.assertEqual(value, ra.release_tag)
# Set/Get of a parallel run attribute using direct access fails.
self.assertRaises(AttributeError, setattr, ra, "unittest_value", value)
self.assertRaises(AttributeError, getattr, ra, "unittest_value")
# Set/Get of a parallel run attribute with supported interface.
ra.SetParallel("unittest_value", value)
self.assertEqual(value, ra.GetParallel("unittest_value"))
# Set/Get a board parallel run attribute, testing both the encouraged
# interface and the underlying interface.
ra.RegisterBoardAttrs(self.BOARD, self.TARGET)
ra.SetBoardParallel(self.BATTR, value, self.BOARD, self.TARGET)
self.assertEqual(
value, ra.GetBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
def testSetDefault(self):
"""Test setting default value of parallel run attributes."""
ra = self._NewRunAttributes()
value = "foobar"
# Attribute starts off not set.
self.assertFalse(ra.HasParallel("unittest_value"))
# Use SetParallelDefault to set it.
ra.SetParallelDefault("unittest_value", value)
self.assertTrue(ra.HasParallel("unittest_value"))
self.assertEqual(value, ra.GetParallel("unittest_value"))
# Calling SetParallelDefault again has no effect.
ra.SetParallelDefault("unittest_value", "junk")
self.assertTrue(ra.HasParallel("unittest_value"))
self.assertEqual(value, ra.GetParallel("unittest_value"))
# Run through same sequence for a board-specific attribute.
with self.assertRaises(AssertionError):
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
ra.RegisterBoardAttrs(self.BOARD, self.TARGET)
self.assertFalse(
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
# Use SetBoardParallelDefault to set it.
ra.SetBoardParallelDefault(self.BATTR, value, self.BOARD, self.TARGET)
self.assertTrue(
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
self.assertEqual(
value, ra.GetBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
# Calling SetBoardParallelDefault again has no effect.
ra.SetBoardParallelDefault(self.BATTR, "junk", self.BOARD, self.TARGET)
self.assertTrue(
ra.HasBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
self.assertEqual(
value, ra.GetBoardParallel(self.BATTR, self.BOARD, self.TARGET)
)
def testAttributeError(self):
"""Test accessing run attributes that do not exist."""
ra = self._NewRunAttributes()
value = "foobar"
# Set/Get on made up attribute name.
self.assertRaises(AttributeError, setattr, ra, "foo", value)
self.assertRaises(AttributeError, getattr, ra, "foo")
# A board/target value is valid, but only if it is registered first.
self.assertRaises(
AssertionError,
ra.GetBoardParallel,
self.BATTR,
self.BOARD,
self.TARGET,
)
ra.RegisterBoardAttrs(self.BOARD, self.TARGET)
self.assertRaises(
AttributeError,
ra.GetBoardParallel,
self.BATTR,
self.BOARD,
self.TARGET,
)
class BoardRunAttributesTest(_BuilderRunTestCase):
"""Test the BoardRunAttributes class."""
BOARD = "SomeBoard"
TARGET = "SomeConfigName"
VALUE = "AnyValueWillDo"
# Any valid board-specific attribute will work here.
BATTR = "breakpad_symbols_generated"
class _SetAttr(object):
"""Stage-like class to set attr on a BoardRunAttributes obj."""
def __init__(self, bra, attr, value, delay=1):
self.bra = bra
self.attr = attr
self.value = value
self.delay = delay
def Run(self):
if self.delay:
time.sleep(self.delay)
self.bra.SetParallel(self.attr, self.value)
class _WaitForAttr(object):
"""Stage-like class to wait for attr on BoardRunAttributes obj."""
def __init__(self, bra, attr, expected_value, timeout=10):
self.bra = bra
self.attr = attr
self.expected_value = expected_value
self.timeout = timeout
def GetParallel(self):
return self.bra.GetParallel(self.attr, timeout=self.timeout)
class _CheckWaitForAttr(_WaitForAttr):
"""Stage-like class to wait for then check attr on BoardRunAttributes."""
def Run(self):
value = self.GetParallel()
assert (
value == self.expected_value
), "For run attribute %s expected value %r but got %r." % (
self.attr,
self.expected_value,
value,
)
class _TimeoutWaitForAttr(_WaitForAttr):
"""Stage-like class to time-out waiting for attr on BoardRunAttributes."""
def Run(self):
try:
self.GetParallel()
assert False, "Expected AttrTimeoutError"
except cbuildbot_run.AttrTimeoutError:
pass
def setUp(self):
self.ra = self._NewRunAttributes()
self.bra = self.ra.RegisterBoardAttrs(self.BOARD, self.TARGET)
def _TestParallelSetGet(self, stage_args):
"""Helper to run "stages" in parallel, according to |stage_args|.
Args:
stage_args: List of tuples of the form (stage_object, extra_args, ...)
where stage_object has a Run method which takes a BoardRunAttributes
object as the first argument and extra_args for the remaining arguments.
"""
stages = [a[0](self.bra, *a[1:]) for a in stage_args]
steps = [stage.Run for stage in stages]
parallel.RunParallelSteps(steps)
def testParallelSetGetFast(self):
"""Pass the parallel run attribute around with no delay."""
stage_args = [
(self._CheckWaitForAttr, self.BATTR, self.VALUE),
(self._SetAttr, self.BATTR, self.VALUE),
]
self._TestParallelSetGet(stage_args)
self.assertRaises(AttributeError, getattr, self.bra, self.BATTR)
self.assertEqual(self.VALUE, self.bra.GetParallel(self.BATTR))
def testParallelSetGetSlow(self):
"""Pass the parallel run attribute around with a delay."""
stage_args = [
(self._SetAttr, self.BATTR, self.VALUE, 10),
(self._TimeoutWaitForAttr, self.BATTR, self.VALUE, 2),
]
self._TestParallelSetGet(stage_args)
self.assertEqual(self.VALUE, self.bra.GetParallel(self.BATTR))
def testParallelSetGetManyGets(self):
"""Set the parallel run attribute in one stage, access in many stages."""
stage_args = [
(self._SetAttr, self.BATTR, self.VALUE, 8),
(self._CheckWaitForAttr, self.BATTR, self.VALUE, 16),
(self._CheckWaitForAttr, self.BATTR, self.VALUE, 16),
(self._CheckWaitForAttr, self.BATTR, self.VALUE, 16),
(self._TimeoutWaitForAttr, self.BATTR, self.VALUE, 1),
]
self._TestParallelSetGet(stage_args)
self.assertEqual(self.VALUE, self.bra.GetParallel(self.BATTR))
def testParallelSetGetManySets(self):
"""Set the parallel run attribute in many stages, access in one stage."""
# Three "stages" set the value, with increasing delays. The stage that
# checks the value should get the first value set.
stage_args = [
(self._SetAttr, self.BATTR, self.VALUE + "1", 1),
(self._SetAttr, self.BATTR, self.VALUE + "2", 11),
(self._CheckWaitForAttr, self.BATTR, self.VALUE + "1", 12),
]
self._TestParallelSetGet(stage_args)
self.assertEqual(self.VALUE + "2", self.bra.GetParallel(self.BATTR))
def testSetGet(self):
"""Test that board-specific attrs do not work with set/get directly."""
self.assertRaises(
AttributeError,
setattr,
self.bra,
"breakpad_symbols_generated",
self.VALUE,
)
self.assertRaises(
AttributeError, getattr, self.bra, "breakpad_symbols_generated"
)
def testAccessRegularRunAttr(self):
"""Test that regular attributes are not known to BoardRunAttributes."""
self.assertRaises(AttributeError, getattr, self.bra, "release_tag")
self.assertRaises(
AttributeError, setattr, self.bra, "release_tag", "foo"
)