"Fossies" - the Fresh Open Source Software Archive

Member "buildbot-2.5.1/buildbot/test/unit/test_plugins.py" (24 Nov 2019, 8780 Bytes) of package /linux/misc/buildbot-2.5.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # This file is part of Buildbot.  Buildbot is free software: you can
    2 # redistribute it and/or modify it under the terms of the GNU General Public
    3 # License as published by the Free Software Foundation, version 2.
    4 #
    5 # This program is distributed in the hope that it will be useful, but WITHOUT
    6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    8 # details.
    9 #
   10 # You should have received a copy of the GNU General Public License along with
   11 # this program; if not, write to the Free Software Foundation, Inc., 51
   12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   13 #
   14 # Copyright Buildbot Team Members
   15 """
   16 Unit tests for the plugin framework
   17 """
   18 
   19 import mock
   20 
   21 from twisted.trial import unittest
   22 from zope.interface import implementer
   23 
   24 import buildbot.plugins.db
   25 from buildbot.errors import PluginDBError
   26 from buildbot.interfaces import IPlugin
   27 
   28 # buildbot.plugins.db needs to be imported for patching, however just 'db' is
   29 # much shorter for using in tests
   30 db = buildbot.plugins.db
   31 
   32 
   33 class FakeEntry:
   34 
   35     """
   36     An entry suitable for unit tests
   37     """
   38 
   39     def __init__(self, name, project_name, version, fail_require, value):
   40         self._name = name
   41         self._dist = mock.Mock(spec_set=['project_name', 'version'])
   42         self._dist.project_name = project_name
   43         self._dist.version = version
   44         self._fail_require = fail_require
   45         self._value = value
   46 
   47     @property
   48     def name(self):
   49         "entry name"
   50         return self._name
   51 
   52     @property
   53     def dist(self):
   54         "dist thingie"
   55         return self._dist
   56 
   57     def require(self):
   58         """
   59         handle external dependencies
   60         """
   61         if self._fail_require:
   62             raise RuntimeError('Fail require as requested')
   63 
   64     def load(self):
   65         """
   66         handle loading
   67         """
   68         return self._value
   69 
   70 
   71 class ITestInterface(IPlugin):
   72 
   73     """
   74     test interface
   75     """
   76     def hello(name):
   77         "Greets by :param:`name`"
   78 
   79 
   80 @implementer(ITestInterface)
   81 class ClassWithInterface:
   82 
   83     """
   84     a class to implement a simple interface
   85     """
   86 
   87     def __init__(self, name=None):
   88         self._name = name
   89 
   90     def hello(self, name=None):
   91         'implement the required method'
   92         return name or self._name
   93 
   94 
   95 class ClassWithNoInterface:
   96 
   97     """
   98     just a class
   99     """
  100 
  101 
  102 # NOTE: buildbot.plugins.db prepends the group with common namespace --
  103 # 'buildbot.'
  104 _FAKE_ENTRIES = {
  105     'buildbot.interface': [
  106         FakeEntry('good', 'non-existent', 'irrelevant', False,
  107                   ClassWithInterface),
  108         FakeEntry('deep.path', 'non-existent', 'irrelevant', False,
  109                   ClassWithInterface)
  110     ],
  111     'buildbot.interface_failed': [
  112         FakeEntry('good', 'non-existent', 'irrelevant', True,
  113                   ClassWithInterface)
  114     ],
  115     'buildbot.no_interface': [
  116         FakeEntry('good', 'non-existent', 'irrelevant', False,
  117                   ClassWithNoInterface)
  118     ],
  119     'buildbot.no_interface_again': [
  120         FakeEntry('good', 'non-existent', 'irrelevant', False,
  121                   ClassWithNoInterface)
  122     ],
  123     'buildbot.no_interface_failed': [
  124         FakeEntry('good', 'non-existent', 'irrelevant', True,
  125                   ClassWithNoInterface)
  126     ],
  127     'buildbot.duplicates': [
  128         FakeEntry('good', 'non-existent', 'first', False,
  129                   ClassWithNoInterface),
  130         FakeEntry('good', 'non-existent', 'second', False,
  131                   ClassWithNoInterface)
  132     ]
  133 }
  134 
  135 
  136 def provide_fake_entries(group):
  137     """
  138     give a set of fake entries for known groups
  139     """
  140     return _FAKE_ENTRIES.get(group, [])
  141 
  142 
  143 @mock.patch('buildbot.plugins.db.iter_entry_points', provide_fake_entries)
  144 class TestBuildbotPlugins(unittest.TestCase):
  145 
  146     def setUp(self):
  147         buildbot.plugins.db._DB = buildbot.plugins.db._PluginDB()
  148 
  149     def test_check_group_registration(self):
  150         with mock.patch.object(buildbot.plugins.db, '_DB', db._PluginDB()):
  151             # The groups will be prepended with namespace, so info() will
  152             # return a dictionary with right keys, but no data
  153             groups = set(_FAKE_ENTRIES.keys())
  154             for group in groups:
  155                 db.get_plugins(group)
  156 
  157             registered = set(db.info().keys())
  158             self.assertEqual(registered, groups)
  159             self.assertEqual(registered, set(db.namespaces()))
  160 
  161     def test_interface_provided_simple(self):
  162         # Basic check before the actual test
  163         self.assertTrue(ITestInterface.implementedBy(ClassWithInterface))
  164 
  165         plugins = db.get_plugins('interface', interface=ITestInterface)
  166 
  167         self.assertTrue('good' in plugins.names)
  168 
  169         result_get = plugins.get('good')
  170         result_getattr = plugins.good
  171         self.assertFalse(result_get is None)
  172         self.assertTrue(result_get is result_getattr)
  173 
  174         # Make sure we actually got our class
  175         greeter = result_get('yes')
  176         self.assertEqual('yes', greeter.hello())
  177         self.assertEqual('no', greeter.hello('no'))
  178 
  179     def test_missing_plugin(self):
  180         plugins = db.get_plugins('interface', interface=ITestInterface)
  181 
  182         with self.assertRaises(AttributeError):
  183             getattr(plugins, 'bad')
  184         with self.assertRaises(PluginDBError):
  185             plugins.get('bad')
  186         with self.assertRaises(PluginDBError):
  187             plugins.get('good.extra')
  188 
  189     def test_interface_provided_deep(self):
  190         # Basic check before the actual test
  191         self.assertTrue(ITestInterface.implementedBy(ClassWithInterface))
  192 
  193         plugins = db.get_plugins('interface', interface=ITestInterface)
  194 
  195         self.assertTrue('deep.path' in plugins.names)
  196 
  197         self.assertTrue('deep.path' in plugins)
  198         self.assertFalse('even.deeper.path' in plugins)
  199 
  200         result_get = plugins.get('deep.path')
  201         result_getattr = plugins.deep.path
  202         self.assertFalse(result_get is None)
  203         self.assertTrue(result_get is result_getattr)
  204 
  205         # Make sure we actually got our class
  206         greeter = result_get('yes')
  207         self.assertEqual('yes', greeter.hello())
  208         self.assertEqual('no', greeter.hello('no'))
  209 
  210     def test_interface_provided_deps_failed(self):
  211         plugins = db.get_plugins('interface_failed', interface=ITestInterface,
  212                                  check_extras=True)
  213         with self.assertRaises(PluginDBError):
  214             plugins.get('good')
  215 
  216     def test_required_interface_not_provided(self):
  217         plugins = db.get_plugins('no_interface_again',
  218                                  interface=ITestInterface)
  219         self.assertTrue(plugins._interface is ITestInterface)
  220         with self.assertRaises(PluginDBError):
  221             plugins.get('good')
  222 
  223     def test_no_interface_provided(self):
  224         plugins = db.get_plugins('no_interface')
  225         self.assertFalse(plugins.get('good') is None)
  226 
  227     def test_no_interface_provided_deps_failed(self):
  228         plugins = db.get_plugins('no_interface_failed', check_extras=True)
  229         with self.assertRaises(PluginDBError):
  230             plugins.get('good')
  231 
  232     def test_failure_on_dups(self):
  233         with self.assertRaises(PluginDBError):
  234             db.get_plugins('duplicates', load_now=True)
  235 
  236     def test_get_info_on_a_known_plugin(self):
  237         plugins = db.get_plugins('interface')
  238         self.assertEqual(('non-existent', 'irrelevant'), plugins.info('good'))
  239 
  240     def test_failure_on_unknown_plugin_info(self):
  241         plugins = db.get_plugins('interface')
  242         with self.assertRaises(PluginDBError):
  243             plugins.info('bad')
  244 
  245     def test_failure_on_unknown_plugin_get(self):
  246         plugins = db.get_plugins('interface')
  247         with self.assertRaises(PluginDBError):
  248             plugins.get('bad')
  249 
  250 
  251 class SimpleFakeEntry(FakeEntry):
  252 
  253     def __init__(self, name, value):
  254         super().__init__(name, 'non-existent', 'irrelevant', False, value)
  255 
  256 
  257 _WORKER_FAKE_ENTRIES = {
  258     'buildbot.worker': [
  259         SimpleFakeEntry('Worker', ClassWithInterface),
  260         SimpleFakeEntry('EC2LatentWorker', ClassWithInterface),
  261         SimpleFakeEntry('LibVirtWorker', ClassWithInterface),
  262         SimpleFakeEntry('OpenStackLatentWorker', ClassWithInterface),
  263         SimpleFakeEntry('newthirdparty', ClassWithInterface),
  264         SimpleFakeEntry('deep.newthirdparty', ClassWithInterface),
  265     ],
  266     'buildbot.util': [
  267         SimpleFakeEntry('WorkerLock', ClassWithInterface),
  268         SimpleFakeEntry('enforceChosenWorker', ClassWithInterface),
  269         SimpleFakeEntry('WorkerChoiceParameter', ClassWithInterface),
  270     ],
  271 }
  272 
  273 
  274 def provide_worker_fake_entries(group):
  275     """
  276     give a set of fake entries for known groups
  277     """
  278     return _WORKER_FAKE_ENTRIES.get(group, [])