blob: e510d4c1940ccfae53a4872efa519b59a2f40854 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# 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."""
from __future__ import print_function
import pickle
import sys
import time
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
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
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.assertTrue(isinstance(run.attrs, cbuildbot_run.RunAttributes))
self.assertTrue(isinstance(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.assertTrue(isinstance(crun.attrs, cbuildbot_run.RunAttributes))
self.assertTrue(isinstance(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')