diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/test/unit/test_config.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/test/unit/test_config.py | 1207 |
1 files changed, 0 insertions, 1207 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/test/unit/test_config.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/test/unit/test_config.py deleted file mode 100644 index 9b6f6c1d..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/test/unit/test_config.py +++ /dev/null @@ -1,1207 +0,0 @@ -# This file is part of Buildbot. Buildbot is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright Buildbot Team Members - -from __future__ import with_statement - -import re -import os -import textwrap -import mock -import __builtin__ -from zope.interface import implements -from twisted.trial import unittest -from twisted.application import service -from twisted.internet import defer -from buildbot import config, buildslave, interfaces, revlinks, locks -from buildbot.process import properties, factory -from buildbot.test.util import dirs, compat -from buildbot.test.util.config import ConfigErrorsMixin -from buildbot.changes import base as changes_base -from buildbot.schedulers import base as schedulers_base -from buildbot.status import base as status_base - -global_defaults = dict( - title='Buildbot', - titleURL='http://buildbot.net', - buildbotURL='http://localhost:8080/', - changeHorizon=None, - eventHorizon=50, - logHorizon=None, - buildHorizon=None, - logCompressionLimit=4096, - logCompressionMethod='bz2', - logMaxTailSize=None, - logMaxSize=None, - properties=properties.Properties(), - mergeRequests=None, - prioritizeBuilders=None, - slavePortnum=None, - multiMaster=False, - debugPassword=None, - manhole=None, -) - - -class FakeChangeSource(changes_base.ChangeSource): - pass - - -class FakeStatusReceiver(status_base.StatusReceiver): - pass - - -class FakeScheduler(object): - implements(interfaces.IScheduler) - def __init__(self, name): - self.name = name - -class FakeBuilder(object): - - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - -class ConfigErrors(unittest.TestCase): - - def test_constr(self): - ex = config.ConfigErrors(['a', 'b']) - self.assertEqual(ex.errors, ['a', 'b']) - - def test_addError(self): - ex = config.ConfigErrors(['a']) - ex.addError('c') - self.assertEqual(ex.errors, ['a', 'c']) - - def test_nonempty(self): - empty = config.ConfigErrors() - full = config.ConfigErrors(['a']) - self.failUnless(not empty) - self.failIf(not full) - - def test_error_raises(self): - e = self.assertRaises(config.ConfigErrors, config.error, "message") - self.assertEqual(e.errors, ["message"]) - - def test_error_no_raise(self): - e = config.ConfigErrors() - self.patch(config, "_errors", e) - config.error("message") - self.assertEqual(e.errors, ["message"]) - - def test_str(self): - ex = config.ConfigErrors() - self.assertEqual(str(ex), "") - - ex = config.ConfigErrors(["a"]) - self.assertEqual(str(ex), "a") - - ex = config.ConfigErrors(["a", "b"]) - self.assertEqual(str(ex), "a\nb") - - ex = config.ConfigErrors(["a"]) - ex.addError('c') - self.assertEqual(str(ex), "a\nc") - - -class MasterConfig(ConfigErrorsMixin, dirs.DirsMixin, unittest.TestCase): - - def setUp(self): - self.basedir = os.path.abspath('basedir') - self.filename = os.path.join(self.basedir, 'test.cfg') - return self.setUpDirs('basedir') - - def tearDown(self): - return self.tearDownDirs() - - # utils - - def patch_load_helpers(self): - # patch out all of the "helpers" for laodConfig with null functions - for n in dir(config.MasterConfig): - if n.startswith('load_'): - typ = 'loader' - elif n.startswith('check_'): - typ = 'checker' - else: - continue - - v = getattr(config.MasterConfig, n) - if callable(v): - if typ == 'loader': - self.patch(config.MasterConfig, n, - mock.Mock(side_effect= - lambda filename, config_dict: None)) - else: - self.patch(config.MasterConfig, n, - mock.Mock(side_effect= - lambda: None)) - - - def install_config_file(self, config_file, other_files={}): - config_file = textwrap.dedent(config_file) - with open(os.path.join(self.basedir, self.filename), "w") as f: - f.write(config_file) - for file, contents in other_files.items(): - with open(file, "w") as f: - f.write(contents) - - - # tests - - def test_defaults(self): - cfg = config.MasterConfig() - expected = dict( - #validation, - db=dict( - db_url='sqlite:///state.sqlite', - db_poll_interval=None), - metrics = None, - caches = dict(Changes=10, Builds=15), - schedulers = {}, - builders = [], - slaves = [], - change_sources = [], - status = [], - user_managers = [], - revlink = revlinks.default_revlink_matcher - ) - expected.update(global_defaults) - got = dict([ - (attr, getattr(cfg, attr)) - for attr, exp in expected.iteritems() ]) - self.assertEqual(got, expected) - - def test_defaults_validation(self): - # re's aren't comparable, but we can make sure the keys match - cfg = config.MasterConfig() - self.assertEqual(sorted(cfg.validation.keys()), - sorted([ - 'branch', 'revision', 'property_name', 'property_value', - ])) - - def test_loadConfig_missing_file(self): - self.assertRaisesConfigError( - re.compile("configuration file .* does not exist"), - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - def test_loadConfig_missing_basedir(self): - self.assertRaisesConfigError( - re.compile("basedir .* does not exist"), - lambda : config.MasterConfig.loadConfig( - os.path.join(self.basedir, 'NO'), 'test.cfg')) - - def test_loadConfig_open_error(self): - """ - Check that loadConfig() raises correct ConfigError exception in cases - when configure file is found, but we fail to open it. - """ - - def raise_IOError(*args): - raise IOError("error_msg") - - self.install_config_file('#dummy') - - # override build-in open() function to always rise IOError - self.patch(__builtin__, "open", raise_IOError) - - # check that we got the expected ConfigError exception - self.assertRaisesConfigError( - re.compile("unable to open configuration file .*: error_msg"), - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - @compat.usesFlushLoggedErrors - def test_loadConfig_parse_error(self): - self.install_config_file('def x:\nbar') - self.assertRaisesConfigError( - re.compile("error while parsing.*traceback in logfile"), - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - self.assertEqual(len(self.flushLoggedErrors(SyntaxError)), 1) - - def test_loadConfig_eval_ConfigError(self): - self.install_config_file("""\ - from buildbot import config - BuildmasterConfig = { 'multiMaster': True } - config.error('oh noes!')""") - self.assertRaisesConfigError("oh noes", - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - def test_loadConfig_eval_ConfigErrors(self): - # We test a config that has embedded errors, as well - # as semantic errors that get added later. If an exception is raised - # prematurely, then the semantic errors wouldn't get reported. - self.install_config_file("""\ - from buildbot import config - BuildmasterConfig = {} - config.error('oh noes!') - config.error('noes too!')""") - e = self.assertRaises(config.ConfigErrors, - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - self.assertEqual(e.errors, ['oh noes!', 'noes too!', - 'no slaves are configured', - 'no builders are configured']) - - def test_loadConfig_no_BuildmasterConfig(self): - self.install_config_file('x=10') - self.assertRaisesConfigError("does not define 'BuildmasterConfig'", - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - def test_loadConfig_unknown_key(self): - self.patch_load_helpers() - self.install_config_file("""\ - BuildmasterConfig = dict(foo=10) - """) - self.assertRaisesConfigError("Unknown BuildmasterConfig key foo", - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - def test_loadConfig_unknown_keys(self): - self.patch_load_helpers() - self.install_config_file("""\ - BuildmasterConfig = dict(foo=10, bar=20) - """) - self.assertRaisesConfigError("Unknown BuildmasterConfig keys bar, foo", - lambda : config.MasterConfig.loadConfig( - self.basedir, self.filename)) - - def test_loadConfig_success(self): - self.patch_load_helpers() - self.install_config_file("""\ - BuildmasterConfig = dict() - """) - rv = config.MasterConfig.loadConfig( - self.basedir, self.filename) - self.assertIsInstance(rv, config.MasterConfig) - - # make sure all of the loaders and checkers are called - self.failUnless(rv.load_global.called) - self.failUnless(rv.load_validation.called) - self.failUnless(rv.load_db.called) - self.failUnless(rv.load_metrics.called) - self.failUnless(rv.load_caches.called) - self.failUnless(rv.load_schedulers.called) - self.failUnless(rv.load_builders.called) - self.failUnless(rv.load_slaves.called) - self.failUnless(rv.load_change_sources.called) - self.failUnless(rv.load_status.called) - self.failUnless(rv.load_user_managers.called) - - self.failUnless(rv.check_single_master.called) - self.failUnless(rv.check_schedulers.called) - self.failUnless(rv.check_locks.called) - self.failUnless(rv.check_builders.called) - self.failUnless(rv.check_status.called) - self.failUnless(rv.check_horizons.called) - self.failUnless(rv.check_slavePortnum.called) - - def test_loadConfig_with_local_import(self): - self.patch_load_helpers() - self.install_config_file("""\ - from subsidiary_module import x - BuildmasterConfig = dict() - """, - {'basedir/subsidiary_module.py' : "x = 10"}) - rv = config.MasterConfig.loadConfig( - self.basedir, self.filename) - self.assertIsInstance(rv, config.MasterConfig) - - -class MasterConfig_loaders(ConfigErrorsMixin, unittest.TestCase): - - filename = 'test.cfg' - - def setUp(self): - self.cfg = config.MasterConfig() - self.errors = config.ConfigErrors() - self.patch(config, '_errors', self.errors) - - # utils - - def assertResults(self, **expected): - self.failIf(self.errors, self.errors.errors) - got = dict([ - (attr, getattr(self.cfg, attr)) - for attr, exp in expected.iteritems() ]) - self.assertEqual(got, expected) - - # tests - - def test_load_global_defaults(self): - self.cfg.load_global(self.filename, {}) - self.assertResults(**global_defaults) - - def test_load_global_string_param_not_string(self): - self.cfg.load_global(self.filename, - dict(title=10)) - self.assertConfigError(self.errors, 'must be a string') - - def test_load_global_int_param_not_int(self): - self.cfg.load_global(self.filename, - dict(changeHorizon='yes')) - self.assertConfigError(self.errors, 'must be an int') - - def do_test_load_global(self, config_dict, **expected): - self.cfg.load_global(self.filename, config_dict) - self.assertResults(**expected) - - def test_load_global_title(self): - self.do_test_load_global(dict(title='hi'), title='hi') - - def test_load_global_projectURL(self): - self.do_test_load_global(dict(projectName='hey'), title='hey') - - def test_load_global_titleURL(self): - self.do_test_load_global(dict(titleURL='hi'), titleURL='hi') - - def test_load_global_buildbotURL(self): - self.do_test_load_global(dict(buildbotURL='hey'), buildbotURL='hey') - - def test_load_global_changeHorizon(self): - self.do_test_load_global(dict(changeHorizon=10), changeHorizon=10) - - def test_load_global_changeHorizon_none(self): - self.do_test_load_global(dict(changeHorizon=None), changeHorizon=None) - - def test_load_global_eventHorizon(self): - self.do_test_load_global(dict(eventHorizon=10), eventHorizon=10) - - def test_load_global_logHorizon(self): - self.do_test_load_global(dict(logHorizon=10), logHorizon=10) - - def test_load_global_buildHorizon(self): - self.do_test_load_global(dict(buildHorizon=10), buildHorizon=10) - - def test_load_global_logCompressionLimit(self): - self.do_test_load_global(dict(logCompressionLimit=10), - logCompressionLimit=10) - - def test_load_global_logCompressionMethod(self): - self.do_test_load_global(dict(logCompressionMethod='gz'), - logCompressionMethod='gz') - - def test_load_global_logCompressionMethod_invalid(self): - self.cfg.load_global(self.filename, - dict(logCompressionMethod='foo')) - self.assertConfigError(self.errors, "must be 'bz2' or 'gz'") - - def test_load_global_codebaseGenerator(self): - func = lambda _: "dummy" - self.do_test_load_global(dict(codebaseGenerator=func), - codebaseGenerator=func) - - def test_load_global_codebaseGenerator_invalid(self): - self.cfg.load_global(self.filename, - dict(codebaseGenerator='dummy')) - self.assertConfigError(self.errors, - "codebaseGenerator must be a callable " - "accepting a dict and returning a str") - - def test_load_global_logMaxSize(self): - self.do_test_load_global(dict(logMaxSize=123), logMaxSize=123) - - def test_load_global_logMaxTailSize(self): - self.do_test_load_global(dict(logMaxTailSize=123), logMaxTailSize=123) - - def test_load_global_properties(self): - exp = properties.Properties() - exp.setProperty('x', 10, self.filename) - self.do_test_load_global(dict(properties=dict(x=10)), properties=exp) - - def test_load_global_properties_invalid(self): - self.cfg.load_global(self.filename, - dict(properties='yes')) - self.assertConfigError(self.errors, "must be a dictionary") - - def test_load_global_mergeRequests_bool(self): - self.do_test_load_global(dict(mergeRequests=False), - mergeRequests=False) - - def test_load_global_mergeRequests_callable(self): - callable = lambda : None - self.do_test_load_global(dict(mergeRequests=callable), - mergeRequests=callable) - - def test_load_global_mergeRequests_invalid(self): - self.cfg.load_global(self.filename, - dict(mergeRequests='yes')) - self.assertConfigError(self.errors, - "must be a callable, True, or False") - - def test_load_global_prioritizeBuilders_callable(self): - callable = lambda : None - self.do_test_load_global(dict(prioritizeBuilders=callable), - prioritizeBuilders=callable) - - def test_load_global_prioritizeBuilders_invalid(self): - self.cfg.load_global(self.filename, - dict(prioritizeBuilders='yes')) - self.assertConfigError(self.errors, "must be a callable") - - def test_load_global_slavePortnum_int(self): - self.do_test_load_global(dict(slavePortnum=123), - slavePortnum='tcp:123') - - def test_load_global_slavePortnum_str(self): - self.do_test_load_global(dict(slavePortnum='udp:123'), - slavePortnum='udp:123') - - def test_load_global_multiMaster(self): - self.do_test_load_global(dict(multiMaster=1), multiMaster=1) - - def test_load_global_debugPassword(self): - self.do_test_load_global(dict(debugPassword='xyz'), - debugPassword='xyz') - - def test_load_global_manhole(self): - mh = mock.Mock(name='manhole') - self.do_test_load_global(dict(manhole=mh), manhole=mh) - - def test_load_global_revlink_callable(self): - callable = lambda : None - self.do_test_load_global(dict(revlink=callable), - revlink=callable) - - def test_load_global_revlink_invalid(self): - self.cfg.load_global(self.filename, dict(revlink='')) - self.assertConfigError(self.errors, "must be a callable") - - def test_load_validation_defaults(self): - self.cfg.load_validation(self.filename, {}) - self.assertEqual(sorted(self.cfg.validation.keys()), - sorted([ - 'branch', 'revision', 'property_name', 'property_value', - ])) - - def test_load_validation_invalid(self): - self.cfg.load_validation(self.filename, - dict(validation='plz')) - self.assertConfigError(self.errors, "must be a dictionary") - - def test_load_validation_unk_keys(self): - self.cfg.load_validation(self.filename, - dict(validation=dict(users='.*'))) - self.assertConfigError(self.errors, "unrecognized validation key(s)") - - def test_load_validation(self): - r = re.compile('.*') - self.cfg.load_validation(self.filename, - dict(validation=dict(branch=r))) - self.assertEqual(self.cfg.validation['branch'], r) - # check that defaults are still around - self.assertIn('revision', self.cfg.validation) - - - def test_load_db_defaults(self): - self.cfg.load_db(self.filename, {}) - self.assertResults( - db=dict(db_url='sqlite:///state.sqlite', db_poll_interval=None)) - - def test_load_db_db_url(self): - self.cfg.load_db(self.filename, dict(db_url='abcd')) - self.assertResults(db=dict(db_url='abcd', db_poll_interval=None)) - - def test_load_db_db_poll_interval(self): - self.cfg.load_db(self.filename, dict(db_poll_interval=2)) - self.assertResults( - db=dict(db_url='sqlite:///state.sqlite', db_poll_interval=2)) - - def test_load_db_dict(self): - self.cfg.load_db(self.filename, - dict(db=dict(db_url='abcd', db_poll_interval=10))) - self.assertResults(db=dict(db_url='abcd', db_poll_interval=10)) - - def test_load_db_unk_keys(self): - self.cfg.load_db(self.filename, - dict(db=dict(db_url='abcd', db_poll_interval=10, bar='bar'))) - self.assertConfigError(self.errors, "unrecognized keys in") - - def test_load_db_not_int(self): - self.cfg.load_db(self.filename, - dict(db=dict(db_url='abcd', db_poll_interval='ten'))) - self.assertConfigError(self.errors, "must be an int") - - - def test_load_metrics_defaults(self): - self.cfg.load_metrics(self.filename, {}) - self.assertResults(metrics=None) - - def test_load_metrics_invalid(self): - self.cfg.load_metrics(self.filename, dict(metrics=13)) - self.assertConfigError(self.errors, "must be a dictionary") - - def test_load_metrics(self): - self.cfg.load_metrics(self.filename, - dict(metrics=dict(foo=1))) - self.assertResults(metrics=dict(foo=1)) - - - def test_load_caches_defaults(self): - self.cfg.load_caches(self.filename, {}) - self.assertResults(caches=dict(Changes=10, Builds=15)) - - def test_load_caches_invalid(self): - self.cfg.load_caches(self.filename, dict(caches=13)) - self.assertConfigError(self.errors, "must be a dictionary") - - def test_load_caches_buildCacheSize(self): - self.cfg.load_caches(self.filename, - dict(buildCacheSize=13)) - self.assertResults(caches=dict(Builds=13, Changes=10)) - - def test_load_caches_buildCacheSize_and_caches(self): - self.cfg.load_caches(self.filename, - dict(buildCacheSize=13, caches=dict(builds=11))) - self.assertConfigError(self.errors, "cannot specify") - - def test_load_caches_changeCacheSize(self): - self.cfg.load_caches(self.filename, - dict(changeCacheSize=13)) - self.assertResults(caches=dict(Changes=13, Builds=15)) - - def test_load_caches_changeCacheSize_and_caches(self): - self.cfg.load_caches(self.filename, - dict(changeCacheSize=13, caches=dict(changes=11))) - self.assertConfigError(self.errors, "cannot specify") - - def test_load_caches(self): - self.cfg.load_caches(self.filename, - dict(caches=dict(foo=1))) - self.assertResults(caches=dict(Changes=10, Builds=15, foo=1)) - - def test_load_caches_entries_test(self): - self.cfg.load_caches(self.filename, - dict(caches=dict(foo="1"))) - self.assertConfigError(self.errors, - "value for cache size 'foo' must be an integer") - - def test_load_schedulers_defaults(self): - self.cfg.load_schedulers(self.filename, {}) - self.assertResults(schedulers={}) - - def test_load_schedulers_not_list(self): - self.cfg.load_schedulers(self.filename, - dict(schedulers=dict())) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_schedulers_not_instance(self): - self.cfg.load_schedulers(self.filename, - dict(schedulers=[mock.Mock()])) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_schedulers_dupe(self): - sch1 = FakeScheduler(name='sch') - sch2 = FakeScheduler(name='sch') - self.cfg.load_schedulers(self.filename, - dict(schedulers=[ sch1, sch2 ])) - self.assertConfigError(self.errors, - "scheduler name 'sch' used multiple times") - - def test_load_schedulers(self): - class Sch(schedulers_base.BaseScheduler): - def __init__(self, name): - self.name = name - sch = Sch('sch') - self.cfg.load_schedulers(self.filename, - dict(schedulers=[sch])) - self.assertResults(schedulers=dict(sch=sch)) - - - def test_load_builders_defaults(self): - self.cfg.load_builders(self.filename, {}) - self.assertResults(builders=[]) - - def test_load_builders_not_list(self): - self.cfg.load_builders(self.filename, - dict(builders=dict())) - self.assertConfigError(self.errors, "must be a list") - - def test_load_builders_not_instance(self): - self.cfg.load_builders(self.filename, - dict(builders=[mock.Mock()])) - self.assertConfigError(self.errors, "is not a builder config (in c['builders']") - - def test_load_builders(self): - bldr = config.BuilderConfig(name='x', - factory=factory.BuildFactory(), slavename='x') - self.cfg.load_builders(self.filename, - dict(builders=[bldr])) - self.assertResults(builders=[bldr]) - - def test_load_builders_dict(self): - bldr = dict(name='x', factory=factory.BuildFactory(), slavename='x') - self.cfg.load_builders(self.filename, - dict(builders=[bldr])) - self.assertIsInstance(self.cfg.builders[0], config.BuilderConfig) - self.assertEqual(self.cfg.builders[0].name, 'x') - - @compat.usesFlushWarnings - def test_load_builders_abs_builddir(self): - bldr = dict(name='x', factory=factory.BuildFactory(), slavename='x', - builddir=os.path.abspath('.')) - self.cfg.load_builders(self.filename, - dict(builders=[bldr])) - self.assertEqual( - len(self.flushWarnings([self.cfg.load_builders])), - 1) - - def test_load_slaves_defaults(self): - self.cfg.load_slaves(self.filename, {}) - self.assertResults(slaves=[]) - - def test_load_slaves_not_list(self): - self.cfg.load_slaves(self.filename, - dict(slaves=dict())) - self.assertConfigError(self.errors, "must be a list") - - def test_load_slaves_not_instance(self): - self.cfg.load_slaves(self.filename, - dict(slaves=[mock.Mock()])) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_slaves_reserved_names(self): - for name in 'debug', 'change', 'status': - self.cfg.load_slaves(self.filename, - dict(slaves=[buildslave.BuildSlave(name, 'x')])) - self.assertConfigError(self.errors, "is reserved") - self.errors.errors[:] = [] # clear out the errors - - def test_load_slaves(self): - sl = buildslave.BuildSlave('foo', 'x') - self.cfg.load_slaves(self.filename, - dict(slaves=[sl])) - self.assertResults(slaves=[sl]) - - - def test_load_change_sources_defaults(self): - self.cfg.load_change_sources(self.filename, {}) - self.assertResults(change_sources=[]) - - def test_load_change_sources_not_instance(self): - self.cfg.load_change_sources(self.filename, - dict(change_source=[mock.Mock()])) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_change_sources_single(self): - chsrc = FakeChangeSource() - self.cfg.load_change_sources(self.filename, - dict(change_source=chsrc)) - self.assertResults(change_sources=[chsrc]) - - def test_load_change_sources_list(self): - chsrc = FakeChangeSource() - self.cfg.load_change_sources(self.filename, - dict(change_source=[chsrc])) - self.assertResults(change_sources=[chsrc]) - - def test_load_status_not_list(self): - self.cfg.load_status(self.filename, dict(status="not-list")) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_status_not_status_rec(self): - self.cfg.load_status(self.filename, dict(status=['fo'])) - self.assertConfigError(self.errors, "must be a list of") - - def test_load_user_managers_defaults(self): - self.cfg.load_user_managers(self.filename, {}) - self.assertResults(user_managers=[]) - - def test_load_user_managers_not_list(self): - self.cfg.load_user_managers(self.filename, - dict(user_managers='foo')) - self.assertConfigError(self.errors, "must be a list") - - def test_load_user_managers(self): - um = mock.Mock() - self.cfg.load_user_managers(self.filename, - dict(user_managers=[um])) - self.assertResults(user_managers=[um]) - -class MasterConfig_checkers(ConfigErrorsMixin, unittest.TestCase): - - def setUp(self): - self.cfg = config.MasterConfig() - self.errors = config.ConfigErrors() - self.patch(config, '_errors', self.errors) - - # utils - - def setup_basic_attrs(self): - # set up a basic config for checking; this will be modified below - sch = mock.Mock() - sch.name = 'sch' - sch.listBuilderNames = lambda : [ 'b1', 'b2' ] - - b1 = mock.Mock() - b1.name = 'b1' - - b2 = mock.Mock() - b2.name = 'b2' - - self.cfg.schedulers = dict(sch=sch) - self.cfg.slaves = [ mock.Mock() ] - self.cfg.builders = [ b1, b2 ] - - def setup_builder_locks(self, - builder_lock=None, - dup_builder_lock=False, - bare_builder_lock=False): - """Set-up two mocked builders with specified locks. - - @type builder_lock: string or None - @param builder_lock: Name of the lock to add to first builder. - If None, no lock is added. - - @type dup_builder_lock: boolean - @param dup_builder_lock: if True, add a lock with duplicate name - to the second builder - - @type dup_builder_lock: boolean - @param bare_builder_lock: if True, add bare lock objects, don't wrap - them into locks.LockAccess object - """ - def bldr(name): - b = mock.Mock() - b.name = name - b.locks = [] - b.factory.steps = [ ('cls', (), dict(locks=[])) ] - return b - - def lock(name): - l = mock.Mock(spec=locks.MasterLock) - l.name = name - if bare_builder_lock: - return l - return locks.LockAccess(l, "counting", _skipChecks=True) - - b1, b2 = bldr('b1'), bldr('b2') - self.cfg.builders = [ b1, b2 ] - if builder_lock: - b1.locks.append(lock(builder_lock)) - if dup_builder_lock: - b2.locks.append(lock(builder_lock)) - - # tests - - def test_check_single_master_multimaster(self): - self.cfg.multiMaster = True - self.cfg.check_single_master() - self.assertNoConfigErrors(self.errors) - - def test_check_single_master_no_builders(self): - self.setup_basic_attrs() - self.cfg.builders = [ ] - self.cfg.check_single_master() - self.assertConfigError(self.errors, "no builders are configured") - - def test_check_single_master_no_slaves(self): - self.setup_basic_attrs() - self.cfg.slaves = [ ] - self.cfg.check_single_master() - self.assertConfigError(self.errors, "no slaves are configured") - - def test_check_single_master_unsch_builder(self): - self.setup_basic_attrs() - b3 = mock.Mock() - b3.name = 'b3' - self.cfg.builders.append(b3) - self.cfg.check_single_master() - self.assertConfigError(self.errors, "have no schedulers to drive them") - - - def test_check_schedulers_unknown_builder(self): - self.setup_basic_attrs() - del self.cfg.builders[1] # remove b2, leaving b1 - - self.cfg.check_schedulers() - self.assertConfigError(self.errors, "Unknown builder 'b2'") - - def test_check_schedulers_ignored_in_multiMaster(self): - self.setup_basic_attrs() - del self.cfg.builders[1] # remove b2, leaving b1 - self.cfg.multiMaster = True - self.cfg.check_schedulers() - self.assertNoConfigErrors(self.errors) - - def test_check_schedulers(self): - self.setup_basic_attrs() - self.cfg.check_schedulers() - self.assertNoConfigErrors(self.errors) - - - def test_check_locks_dup_builder_lock(self): - self.setup_builder_locks(builder_lock='l', dup_builder_lock=True) - self.cfg.check_locks() - self.assertConfigError(self.errors, "Two locks share") - - def test_check_locks(self): - self.setup_builder_locks(builder_lock='bl') - self.cfg.check_locks() - self.assertNoConfigErrors(self.errors) - - def test_check_locks_none(self): - # no locks in the whole config, should be fine - self.setup_builder_locks() - self.cfg.check_locks() - self.assertNoConfigErrors(self.errors) - - def test_check_locks_bare(self): - # check_locks() should be able to handle bare lock object, - # lock objects that are not wrapped into LockAccess() object - self.setup_builder_locks(builder_lock='oldlock', - bare_builder_lock=True) - self.cfg.check_locks() - self.assertNoConfigErrors(self.errors) - - - def test_check_builders_unknown_slave(self): - sl = mock.Mock() - sl.slavename = 'xyz' - self.cfg.slaves = [ sl ] - - b1 = FakeBuilder(slavenames=[ 'xyz', 'abc' ], builddir='x', name='b1') - self.cfg.builders = [ b1 ] - - self.cfg.check_builders() - self.assertConfigError(self.errors, - "builder 'b1' uses unknown slaves 'abc'") - - def test_check_builders_duplicate_name(self): - b1 = FakeBuilder(slavenames=[], name='b1', builddir='1') - b2 = FakeBuilder(slavenames=[], name='b1', builddir='2') - self.cfg.builders = [ b1, b2 ] - - self.cfg.check_builders() - self.assertConfigError(self.errors, - "duplicate builder name 'b1'") - - def test_check_builders_duplicate_builddir(self): - b1 = FakeBuilder(slavenames=[], name='b1', builddir='dir') - b2 = FakeBuilder(slavenames=[], name='b2', builddir='dir') - self.cfg.builders = [ b1, b2 ] - - self.cfg.check_builders() - self.assertConfigError(self.errors, - "duplicate builder builddir 'dir'") - - def test_check_builders(self): - sl = mock.Mock() - sl.slavename = 'a' - self.cfg.slaves = [ sl ] - - b1 = FakeBuilder(slavenames=[ 'a' ], name='b1', builddir='dir1') - b2 = FakeBuilder(slavenames=[ 'a' ], name='b2', builddir='dir2') - self.cfg.builders = [ b1, b2 ] - - self.cfg.check_builders() - self.assertNoConfigErrors(self.errors) - - - def test_check_status_fails(self): - st = FakeStatusReceiver() - st.checkConfig = lambda status: config.error("oh noes") - self.cfg.status = [ st ] - - self.cfg.check_status() - - self.assertConfigError(self.errors, "oh noes") - - def test_check_status(self): - st = FakeStatusReceiver() - st.checkConfig = mock.Mock() - self.cfg.status = [ st ] - - self.cfg.check_status() - - self.assertNoConfigErrors(self.errors) - st.checkConfig.assert_called_once_with(self.cfg.status) - - def test_check_horizons(self): - self.cfg.logHorizon = 100 - self.cfg.buildHorizon = 50 - self.cfg.check_horizons() - - self.assertConfigError(self.errors, "logHorizon must be less") - - def test_check_slavePortnum_set(self): - self.cfg.slavePortnum = 10 - self.cfg.check_slavePortnum() - self.assertNoConfigErrors(self.errors) - - def test_check_slavePortnum_not_set_slaves(self): - self.cfg.slaves = [ mock.Mock() ] - self.cfg.check_slavePortnum() - self.assertConfigError(self.errors, - "slaves are configured, but no slavePortnum is set") - - def test_check_slavePortnum_not_set_debug(self): - self.cfg.debugPassword = 'ssh' - self.cfg.check_slavePortnum() - self.assertConfigError(self.errors, - "debug client is configured, but no slavePortnum is set") - - -class BuilderConfig(ConfigErrorsMixin, unittest.TestCase): - - factory = factory.BuildFactory() - - # utils - - def assertAttributes(self, cfg, **expected): - got = dict([ - (attr, getattr(cfg, attr)) - for attr, exp in expected.iteritems() ]) - self.assertEqual(got, expected) - - # tests - - def test_no_name(self): - self.assertRaisesConfigError( - "builder's name is required", - lambda : config.BuilderConfig( - factory=self.factory, slavenames=['a'])) - - def test_reserved_name(self): - self.assertRaisesConfigError( - "builder names must not start with an underscore: '_a'", - lambda : config.BuilderConfig(name='_a', - factory=self.factory, slavenames=['a'])) - - def test_no_factory(self): - self.assertRaisesConfigError( - "builder 'a' has no factory", - lambda : config.BuilderConfig( - name='a', slavenames=['a'])) - - def test_wrong_type_factory(self): - self.assertRaisesConfigError( - "builder 'a's factory is not", - lambda : config.BuilderConfig( - factory=[], name='a', slavenames=['a'])) - - def test_no_slavenames(self): - self.assertRaisesConfigError( - "builder 'a': at least one slavename is required", - lambda : config.BuilderConfig( - name='a', factory=self.factory)) - - def test_bogus_slavenames(self): - self.assertRaisesConfigError( - "slavenames must be a list or a string", - lambda : config.BuilderConfig( - name='a', slavenames={1:2}, factory=self.factory)) - - def test_bogus_slavename(self): - self.assertRaisesConfigError( - "slavename must be a string", - lambda : config.BuilderConfig( - name='a', slavename=1, factory=self.factory)) - - def test_bogus_category(self): - self.assertRaisesConfigError( - "category must be a string", - lambda : config.BuilderConfig(category=13, - name='a', slavenames=['a'], factory=self.factory)) - - def test_inv_nextSlave(self): - self.assertRaisesConfigError( - "nextSlave must be a callable", - lambda : config.BuilderConfig(nextSlave="foo", - name="a", slavenames=['a'], factory=self.factory)) - - def test_inv_nextBuild(self): - self.assertRaisesConfigError( - "nextBuild must be a callable", - lambda : config.BuilderConfig(nextBuild="foo", - name="a", slavenames=['a'], factory=self.factory)) - - def test_inv_canStartBuild(self): - self.assertRaisesConfigError( - "canStartBuild must be a callable", - lambda : config.BuilderConfig(canStartBuild="foo", - name="a", slavenames=['a'], factory=self.factory)) - - def test_inv_env(self): - self.assertRaisesConfigError( - "builder's env must be a dictionary", - lambda : config.BuilderConfig(env="foo", - name="a", slavenames=['a'], factory=self.factory)) - - def test_defaults(self): - cfg = config.BuilderConfig( - name='a b c', slavename='a', factory=self.factory) - self.assertIdentical(cfg.factory, self.factory) - self.assertAttributes(cfg, - name='a b c', - slavenames=['a'], - builddir='a_b_c', - slavebuilddir='a_b_c', - category='', - nextSlave=None, - locks=[], - env={}, - properties={}, - mergeRequests=None, - description=None) - - def test_args(self): - cfg = config.BuilderConfig( - name='b', slavename='s1', slavenames='s2', builddir='bd', - slavebuilddir='sbd', factory=self.factory, category='c', - nextSlave=lambda : 'ns', nextBuild=lambda : 'nb', locks=['l'], - env=dict(x=10), properties=dict(y=20), mergeRequests='mr', - description='buzz') - self.assertIdentical(cfg.factory, self.factory) - self.assertAttributes(cfg, - name='b', - slavenames=['s2', 's1'], - builddir='bd', - slavebuilddir='sbd', - category='c', - locks=['l'], - env={'x':10}, - properties={'y':20}, - mergeRequests='mr', - description='buzz') - - def test_getConfigDict(self): - ns = lambda : 'ns' - nb = lambda : 'nb' - cfg = config.BuilderConfig( - name='b', slavename='s1', slavenames='s2', builddir='bd', - slavebuilddir='sbd', factory=self.factory, category='c', - nextSlave=ns, nextBuild=nb, locks=['l'], - env=dict(x=10), properties=dict(y=20), mergeRequests='mr', - description='buzz') - self.assertEqual(cfg.getConfigDict(), {'builddir': 'bd', - 'category': 'c', - 'description': 'buzz', - 'env': {'x': 10}, - 'factory': self.factory, - 'locks': ['l'], - 'mergeRequests': 'mr', - 'name': 'b', - 'nextBuild': nb, - 'nextSlave': ns, - 'properties': {'y': 20}, - 'slavebuilddir': 'sbd', - 'slavenames': ['s2', 's1'], - }) - - - -class FakeService(config.ReconfigurableServiceMixin, - service.Service): - - succeed = True - call_index = 1 - - def reconfigService(self, new_config): - self.called = FakeService.call_index - FakeService.call_index += 1 - d = config.ReconfigurableServiceMixin.reconfigService(self, new_config) - if not self.succeed: - @d.addCallback - def fail(_): - raise ValueError("oh noes") - return d - - - -class FakeMultiService(config.ReconfigurableServiceMixin, - service.MultiService): - - def reconfigService(self, new_config): - self.called = True - d = config.ReconfigurableServiceMixin.reconfigService(self, new_config) - return d - - - -class ReconfigurableServiceMixin(unittest.TestCase): - - def test_service(self): - svc = FakeService() - d = svc.reconfigService(mock.Mock()) - @d.addCallback - def check(_): - self.assertTrue(svc.called) - return d - - @defer.inlineCallbacks - def test_service_failure(self): - svc = FakeService() - svc.succeed = False - try: - yield svc.reconfigService(mock.Mock()) - except ValueError: - pass - else: - self.fail("should have raised ValueError") - - def test_multiservice(self): - svc = FakeMultiService() - ch1 = FakeService() - ch1.setServiceParent(svc) - ch2 = FakeMultiService() - ch2.setServiceParent(svc) - ch3 = FakeService() - ch3.setServiceParent(ch2) - d = svc.reconfigService(mock.Mock()) - @d.addCallback - def check(_): - self.assertTrue(svc.called) - self.assertTrue(ch1.called) - self.assertTrue(ch2.called) - self.assertTrue(ch3.called) - return d - - def test_multiservice_priority(self): - parent = FakeMultiService() - svc128 = FakeService() - svc128.setServiceParent(parent) - - services = [ svc128 ] - for i in range(20, 1, -1): - svc = FakeService() - svc.reconfig_priority = i - svc.setServiceParent(parent) - services.append(svc) - - d = parent.reconfigService(mock.Mock()) - @d.addCallback - def check(_): - prio_order = [ svc.called for svc in services ] - called_order = sorted(prio_order) - self.assertEqual(prio_order, called_order) - return d - - @compat.usesFlushLoggedErrors - @defer.inlineCallbacks - def test_multiservice_nested_failure(self): - svc = FakeMultiService() - ch1 = FakeService() - ch1.setServiceParent(svc) - ch1.succeed = False - try: - yield svc.reconfigService(mock.Mock()) - except ValueError: - pass - else: - self.fail("should have raised ValueError") |