"Fossies" - the Fresh Open Source Software Archive

Member "buildbot-2.3.1/buildbot/test/unit/test_util_service.py" (23 May 2019, 27945 Bytes) of package /linux/misc/buildbot-2.3.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. See also the last Fossies "Diffs" side-by-side code changes report for "test_util_service.py": 2.1.0_vs_2.2.0.

    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 import mock
   17 
   18 from twisted.internet import defer
   19 from twisted.internet import task
   20 from twisted.trial import unittest
   21 
   22 from buildbot import config
   23 from buildbot.process.properties import Interpolate
   24 from buildbot.util import service
   25 
   26 
   27 class DeferredStartStop(service.AsyncService):
   28 
   29     def startService(self):
   30         self.d = defer.Deferred()
   31         return self.d
   32 
   33     def stopService(self):
   34         self.d = defer.Deferred()
   35         return self.d
   36 
   37 
   38 class AsyncMultiService(unittest.TestCase):
   39 
   40     def setUp(self):
   41         self.svc = service.AsyncMultiService()
   42 
   43     @defer.inlineCallbacks
   44     def test_empty(self):
   45         yield self.svc.startService()
   46         yield self.svc.stopService()
   47 
   48     def test_waits_for_child_services(self):
   49         child = DeferredStartStop()
   50         child.setServiceParent(self.svc)
   51 
   52         d = self.svc.startService()
   53         self.assertFalse(d.called)
   54         child.d.callback(None)
   55         self.assertTrue(d.called)
   56 
   57         d = self.svc.stopService()
   58         self.assertFalse(d.called)
   59         child.d.callback(None)
   60         self.assertTrue(d.called)
   61 
   62     def test_child_fails(self):
   63         child = DeferredStartStop()
   64         child.setServiceParent(self.svc)
   65 
   66         d = self.svc.startService()
   67         self.assertFalse(d.called)
   68         child.d.errback(RuntimeError('oh noes'))
   69         self.assertTrue(d.called)
   70 
   71         @d.addErrback
   72         def check(f):
   73             f.check(RuntimeError)
   74 
   75         d = self.svc.stopService()
   76         self.assertFalse(d.called)
   77         child.d.errback(RuntimeError('oh noes'))
   78         self.assertTrue(d.called)
   79 
   80         @d.addErrback
   81         def check_again(f):
   82             f.check(RuntimeError)
   83 
   84     def test_child_starts_on_sSP(self):
   85         d = self.svc.startService()
   86         self.assertTrue(d.called)
   87 
   88         child = DeferredStartStop()
   89         d = child.setServiceParent(self.svc)
   90         self.assertFalse(d.called)
   91         child.d.callback(None)
   92         self.assertTrue(d.called)
   93 
   94 
   95 class ClusteredBuildbotService(unittest.TestCase):
   96     SVC_NAME = 'myName'
   97     SVC_ID = 20
   98 
   99     class DummyService(service.ClusteredBuildbotService):
  100         pass
  101 
  102     def setUp(self):
  103         self.svc = self.makeService()
  104 
  105     def tearDown(self):
  106         pass
  107 
  108     def makeService(self, name=SVC_NAME, serviceid=SVC_ID):
  109         svc = self.DummyService(name=name)
  110 
  111         svc.clock = task.Clock()
  112 
  113         self.setServiceClaimable(svc, defer.succeed(False))
  114         self.setActivateToReturn(svc, defer.succeed(None))
  115         self.setDeactivateToReturn(svc, defer.succeed(None))
  116         self.setGetServiceIdToReturn(svc, defer.succeed(serviceid))
  117         self.setUnclaimToReturn(svc, defer.succeed(None))
  118 
  119         return svc
  120 
  121     def makeMock(self, value):
  122         mockObj = mock.Mock()
  123         if isinstance(value, Exception):
  124             mockObj.side_effect = value
  125         else:
  126             mockObj.return_value = value
  127         return mockObj
  128 
  129     def setServiceClaimable(self, svc, claimable):
  130         svc._claimService = self.makeMock(claimable)
  131 
  132     def setGetServiceIdToReturn(self, svc, serviceid):
  133         svc._getServiceId = self.makeMock(serviceid)
  134 
  135     def setUnclaimToReturn(self, svc, unclaim):
  136         svc._unclaimService = self.makeMock(unclaim)
  137 
  138     def setActivateToReturn(self, svc, activate):
  139         svc.activate = self.makeMock(activate)
  140 
  141     def setDeactivateToReturn(self, svc, deactivate):
  142         svc.deactivate = self.makeMock(deactivate)
  143 
  144     def test_name_PreservesUnicodePromotion(self):
  145         svc = self.makeService(name='n')
  146 
  147         self.assertIsInstance(svc.name, str)
  148         self.assertEqual(svc.name, 'n')
  149 
  150     def test_name_GetsUnicodePromotion(self):
  151         svc = self.makeService(name='n')
  152 
  153         self.assertIsInstance(svc.name, str)
  154         self.assertEqual(svc.name, 'n')
  155 
  156     def test_compare(self):
  157         a = self.makeService(name='a', serviceid=20)
  158         b1 = self.makeService(name='b', serviceid=21)
  159         b2 = self.makeService(name='b', serviceid=21)  # same args as 'b1'
  160         b3 = self.makeService(name='b', serviceid=20)  # same id as 'a'
  161 
  162         self.assertTrue(a == a)
  163         self.assertTrue(a != b1)
  164         self.assertTrue(a != b2)
  165         self.assertTrue(a != b3)
  166 
  167         self.assertTrue(b1 != a)
  168         self.assertTrue(b1 == b1)
  169         self.assertTrue(b1 == b2)
  170         self.assertTrue(b1 == b3)
  171 
  172     def test_create_NothingCalled(self):
  173         # None of the member functions get called until startService happens
  174         self.assertFalse(self.svc.activate.called)
  175         self.assertFalse(self.svc.deactivate.called)
  176         self.assertFalse(self.svc._getServiceId.called)
  177         self.assertFalse(self.svc._claimService.called)
  178         self.assertFalse(self.svc._unclaimService.called)
  179 
  180     def test_create_IsInactive(self):
  181         # starts in inactive state
  182         self.assertFalse(self.svc.isActive())
  183 
  184     def test_create_HasNoServiceIdYet(self):
  185         # has no service id at first
  186         self.assertIdentical(self.svc.serviceid, None)
  187 
  188     def test_start_UnclaimableSoNotActiveYet(self):
  189         self.svc.startService()
  190 
  191         self.assertFalse(self.svc.isActive())
  192 
  193     def test_start_GetsServiceIdAssigned(self):
  194         self.svc.startService()
  195 
  196         self.assertEqual(1, self.svc._getServiceId.call_count)
  197         self.assertEqual(1, self.svc._claimService.call_count)
  198 
  199         self.assertEqual(self.SVC_ID, self.svc.serviceid)
  200 
  201     def test_start_WontPollYet(self):
  202         self.svc.startService()
  203 
  204         # right before the poll interval, nothing has tried again yet
  205         self.svc.clock.advance(self.svc.POLL_INTERVAL_SEC * 0.95)
  206 
  207         self.assertEqual(0, self.svc.activate.call_count)
  208         self.assertEqual(1, self.svc._getServiceId.call_count)
  209         self.assertEqual(1, self.svc._claimService.call_count)
  210 
  211         self.assertEqual(0, self.svc.deactivate.call_count)
  212         self.assertEqual(0, self.svc._unclaimService.call_count)
  213 
  214         self.assertFalse(self.svc.isActive())
  215 
  216     @defer.inlineCallbacks
  217     def test_start_PollButClaimFails(self):
  218         yield self.svc.startService()
  219 
  220         # at the POLL time, it gets called again, but we're still inactive...
  221         self.svc.clock.advance(self.svc.POLL_INTERVAL_SEC * 1.05)
  222 
  223         self.assertEqual(0, self.svc.activate.call_count)
  224         self.assertEqual(1, self.svc._getServiceId.call_count)
  225         self.assertEqual(2, self.svc._claimService.call_count)
  226 
  227         self.assertEqual(0, self.svc.deactivate.call_count)
  228         self.assertEqual(0, self.svc._unclaimService.call_count)
  229 
  230         self.assertEqual(False, self.svc.isActive())
  231 
  232     def test_start_PollsPeriodically(self):
  233         NUMBER_OF_POLLS = 15
  234 
  235         self.svc.startService()
  236 
  237         for i in range(NUMBER_OF_POLLS):
  238             self.svc.clock.advance(self.svc.POLL_INTERVAL_SEC)
  239 
  240         self.assertEqual(1, self.svc._getServiceId.call_count)
  241         self.assertEqual(
  242             1 + NUMBER_OF_POLLS, self.svc._claimService.call_count)
  243 
  244     def test_start_ClaimSucceeds(self):
  245         self.setServiceClaimable(self.svc, defer.succeed(True))
  246 
  247         self.svc.startService()
  248 
  249         self.assertEqual(1, self.svc.activate.call_count)
  250         self.assertEqual(1, self.svc._getServiceId.call_count)
  251         self.assertEqual(1, self.svc._claimService.call_count)
  252 
  253         self.assertEqual(0, self.svc.deactivate.call_count)
  254         self.assertEqual(0, self.svc._unclaimService.call_count)
  255 
  256         self.assertEqual(True, self.svc.isActive())
  257 
  258     def test_start_PollingAfterClaimSucceedsDoesNothing(self):
  259         self.setServiceClaimable(self.svc, defer.succeed(True))
  260 
  261         self.svc.startService()
  262 
  263         # another epoch shouldn't do anything further...
  264         self.svc.clock.advance(self.svc.POLL_INTERVAL_SEC * 2)
  265 
  266         self.assertEqual(1, self.svc.activate.call_count)
  267         self.assertEqual(1, self.svc._getServiceId.call_count)
  268         self.assertEqual(1, self.svc._claimService.call_count)
  269 
  270         self.assertEqual(0, self.svc.deactivate.call_count)
  271         self.assertEqual(0, self.svc._unclaimService.call_count)
  272 
  273         self.assertEqual(True, self.svc.isActive())
  274 
  275     def test_stopWhileStarting_NeverActive(self):
  276         self.svc.startService()
  277         #   .. claim fails
  278 
  279         stopDeferred = self.svc.stopService()
  280 
  281         # a stop at this point unwinds things immediately
  282         self.successResultOf(stopDeferred)
  283 
  284         # advance the clock, and nothing should happen
  285         self.svc.clock.advance(self.svc.POLL_INTERVAL_SEC * 2)
  286 
  287         self.assertEqual(1, self.svc._claimService.call_count)
  288         self.assertEqual(0, self.svc._unclaimService.call_count)
  289         self.assertEqual(0, self.svc.deactivate.call_count)
  290 
  291         self.assertFalse(self.svc.isActive())
  292 
  293     def test_stop_AfterActivated(self):
  294         self.setServiceClaimable(self.svc, defer.succeed(True))
  295         self.svc.startService()
  296 
  297         # now deactivate:
  298         stopDeferred = self.svc.stopService()
  299 
  300         # immediately stops
  301         self.successResultOf(stopDeferred)
  302 
  303         self.assertEqual(1, self.svc.activate.call_count)
  304         self.assertEqual(1, self.svc._getServiceId.call_count)
  305         self.assertEqual(1, self.svc._claimService.call_count)
  306 
  307         self.assertEqual(1, self.svc._unclaimService.call_count)
  308         self.assertEqual(1, self.svc.deactivate.call_count)
  309 
  310         self.assertEqual(False, self.svc.isActive())
  311 
  312     def test_stop_AfterActivated_NoDeferred(self):
  313         # set all the child-class functions to return non-deferreds,
  314         # just to check we can handle both:
  315         self.setServiceClaimable(self.svc, True)
  316         self.setActivateToReturn(self.svc, None)
  317         self.setDeactivateToReturn(self.svc, None)
  318         self.setGetServiceIdToReturn(self.svc, self.SVC_ID)
  319         self.setUnclaimToReturn(self.svc, None)
  320 
  321         self.svc.startService()
  322 
  323         # now deactivate:
  324         stopDeferred = self.svc.stopService()
  325 
  326         # immediately stops
  327         self.successResultOf(stopDeferred)
  328 
  329         self.assertEqual(1, self.svc.activate.call_count)
  330         self.assertEqual(1, self.svc._getServiceId.call_count)
  331         self.assertEqual(1, self.svc._claimService.call_count)
  332 
  333         self.assertEqual(1, self.svc._unclaimService.call_count)
  334         self.assertEqual(1, self.svc.deactivate.call_count)
  335 
  336         self.assertEqual(False, self.svc.isActive())
  337 
  338     def test_stopWhileStarting_getServiceIdTakesForever(self):
  339         # create a deferred that will take a while...
  340         svcIdDeferred = defer.Deferred()
  341         self.setGetServiceIdToReturn(self.svc, svcIdDeferred)
  342 
  343         self.setServiceClaimable(self.svc, defer.succeed(True))
  344         self.svc.startService()
  345 
  346         # stop before it has the service id (the svcIdDeferred is stuck)
  347         stopDeferred = self.svc.stopService()
  348 
  349         self.assertNoResult(stopDeferred)
  350 
  351         # .. no deactivates yet....
  352         self.assertEqual(0, self.svc.deactivate.call_count)
  353         self.assertEqual(0, self.svc.activate.call_count)
  354         self.assertEqual(0, self.svc._claimService.call_count)
  355         self.assertEqual(False, self.svc.isActive())
  356 
  357         # then let service id part finish
  358         svcIdDeferred.callback(None)
  359 
  360         # ... which will cause the stop to also finish
  361         self.successResultOf(stopDeferred)
  362 
  363         # and everything else should unwind too:
  364         self.assertEqual(1, self.svc.activate.call_count)
  365         self.assertEqual(1, self.svc._getServiceId.call_count)
  366         self.assertEqual(1, self.svc._claimService.call_count)
  367 
  368         self.assertEqual(1, self.svc.deactivate.call_count)
  369         self.assertEqual(1, self.svc._unclaimService.call_count)
  370 
  371         self.assertEqual(False, self.svc.isActive())
  372 
  373     def test_stopWhileStarting_claimServiceTakesForever(self):
  374         # create a deferred that will take a while...
  375         claimDeferred = defer.Deferred()
  376         self.setServiceClaimable(self.svc, claimDeferred)
  377 
  378         self.svc.startService()
  379         #   .. claim is still pending here
  380 
  381         # stop before it's done activating
  382         stopDeferred = self.svc.stopService()
  383 
  384         self.assertNoResult(stopDeferred)
  385 
  386         # .. no deactivates yet....
  387         self.assertEqual(0, self.svc.activate.call_count)
  388         self.assertEqual(1, self.svc._getServiceId.call_count)
  389         self.assertEqual(1, self.svc._claimService.call_count)
  390         self.assertEqual(0, self.svc.deactivate.call_count)
  391         self.assertEqual(0, self.svc._unclaimService.call_count)
  392         self.assertEqual(False, self.svc.isActive())
  393 
  394         # then let claim succeed, but we should see things unwind
  395         claimDeferred.callback(True)
  396 
  397         # ... which will cause the stop to also finish
  398         self.successResultOf(stopDeferred)
  399 
  400         # and everything else should unwind too:
  401         self.assertEqual(1, self.svc.activate.call_count)
  402         self.assertEqual(1, self.svc._getServiceId.call_count)
  403         self.assertEqual(1, self.svc._claimService.call_count)
  404         self.assertEqual(1, self.svc.deactivate.call_count)
  405         self.assertEqual(1, self.svc._unclaimService.call_count)
  406         self.assertEqual(False, self.svc.isActive())
  407 
  408     def test_stopWhileStarting_activateTakesForever(self):
  409         """If activate takes forever, things acquiesce nicely"""
  410         # create a deferreds that will take a while...
  411         activateDeferred = defer.Deferred()
  412         self.setActivateToReturn(self.svc, activateDeferred)
  413 
  414         self.setServiceClaimable(self.svc, defer.succeed(True))
  415         self.svc.startService()
  416 
  417         # stop before it's done activating
  418         stopDeferred = self.svc.stopService()
  419 
  420         self.assertNoResult(stopDeferred)
  421 
  422         # .. no deactivates yet....
  423         self.assertEqual(1, self.svc.activate.call_count)
  424         self.assertEqual(1, self.svc._getServiceId.call_count)
  425         self.assertEqual(1, self.svc._claimService.call_count)
  426         self.assertEqual(0, self.svc.deactivate.call_count)
  427         self.assertEqual(0, self.svc._unclaimService.call_count)
  428         self.assertEqual(True, self.svc.isActive())
  429 
  430         # then let activate finish
  431         activateDeferred.callback(None)
  432 
  433         # ... which will cause the stop to also finish
  434         self.successResultOf(stopDeferred)
  435 
  436         # and everything else should unwind too:
  437         self.assertEqual(1, self.svc.activate.call_count)
  438         self.assertEqual(1, self.svc._getServiceId.call_count)
  439         self.assertEqual(1, self.svc._claimService.call_count)
  440         self.assertEqual(1, self.svc.deactivate.call_count)
  441         self.assertEqual(1, self.svc._unclaimService.call_count)
  442         self.assertEqual(False, self.svc.isActive())
  443 
  444     def test_stop_unclaimTakesForever(self):
  445         # create a deferred that will take a while...
  446         unclaimDeferred = defer.Deferred()
  447         self.setUnclaimToReturn(self.svc, unclaimDeferred)
  448 
  449         self.setServiceClaimable(self.svc, defer.succeed(True))
  450         self.svc.startService()
  451 
  452         # stop before it's done activating
  453         stopDeferred = self.svc.stopService()
  454 
  455         self.assertNoResult(stopDeferred)
  456 
  457         # .. no deactivates yet....
  458         self.assertEqual(1, self.svc.deactivate.call_count)
  459         self.assertEqual(1, self.svc._unclaimService.call_count)
  460         self.assertEqual(False, self.svc.isActive())
  461 
  462         # then let unclaim part finish
  463         unclaimDeferred.callback(None)
  464         # ... which will cause the stop to finish
  465         self.successResultOf(stopDeferred)
  466 
  467         # and everything should unwind:
  468         self.assertEqual(1, self.svc.deactivate.call_count)
  469         self.assertEqual(1, self.svc._unclaimService.call_count)
  470         self.assertEqual(False, self.svc.isActive())
  471 
  472     def test_stop_deactivateTakesForever(self):
  473         # create a deferred that will take a while...
  474         deactivateDeferred = defer.Deferred()
  475         self.setDeactivateToReturn(self.svc, deactivateDeferred)
  476 
  477         self.setServiceClaimable(self.svc, defer.succeed(True))
  478         self.svc.startService()
  479 
  480         # stop before it's done activating
  481         stopDeferred = self.svc.stopService()
  482 
  483         self.assertNoResult(stopDeferred)
  484 
  485         self.assertEqual(1, self.svc.deactivate.call_count)
  486         self.assertEqual(0, self.svc._unclaimService.call_count)
  487         self.assertEqual(False, self.svc.isActive())
  488 
  489         # then let deactivate finish
  490         deactivateDeferred.callback(None)
  491         # ... which will cause the stop to finish
  492         self.successResultOf(stopDeferred)
  493 
  494         # and everything else should unwind too:
  495         self.assertEqual(1, self.svc.deactivate.call_count)
  496         self.assertEqual(1, self.svc._unclaimService.call_count)
  497         self.assertEqual(False, self.svc.isActive())
  498 
  499     def test_claim_raises(self):
  500         self.setServiceClaimable(self.svc, RuntimeError())
  501 
  502         self.svc.startService()
  503 
  504         self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError)))
  505         self.assertEqual(False, self.svc.isActive())
  506 
  507     @defer.inlineCallbacks
  508     def test_activate_raises(self):
  509         self.setServiceClaimable(self.svc, defer.succeed(True))
  510         self.setActivateToReturn(self.svc, RuntimeError())
  511 
  512         yield self.svc.startService()
  513 
  514         self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError)))
  515         # half-active: we actually return True in this case:
  516         self.assertEqual(True, self.svc.isActive())
  517 
  518     def test_deactivate_raises(self):
  519         self.setServiceClaimable(self.svc, defer.succeed(True))
  520         self.setDeactivateToReturn(self.svc, RuntimeError())
  521 
  522         self.svc.startService()
  523         self.svc.stopService()
  524 
  525         self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError)))
  526         self.assertEqual(False, self.svc.isActive())
  527 
  528     def test_unclaim_raises(self):
  529         self.setServiceClaimable(self.svc, defer.succeed(True))
  530         self.setUnclaimToReturn(self.svc, RuntimeError())
  531 
  532         self.svc.startService()
  533         self.svc.stopService()
  534 
  535         self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError)))
  536         self.assertEqual(False, self.svc.isActive())
  537 
  538 
  539 class MyService(service.BuildbotService):
  540 
  541     def checkConfig(self, foo, a=None):
  542         if a is None:
  543             config.error("a must be specified")
  544         return defer.succeed(True)
  545 
  546     def reconfigService(self, *argv, **kwargs):
  547         self.config = argv, kwargs
  548         return defer.succeed(None)
  549 
  550 
  551 class fakeConfig:
  552     pass
  553 
  554 
  555 class fakeMaster(service.MasterService, service.ReconfigurableServiceMixin):
  556     pass
  557 
  558 
  559 def makeFakeMaster():
  560     m = fakeMaster()
  561     m.db = mock.Mock()
  562     return m
  563 
  564 
  565 class BuildbotService(unittest.TestCase):
  566 
  567     def setUp(self):
  568         self.master = makeFakeMaster()
  569 
  570     @defer.inlineCallbacks
  571     def prepareService(self):
  572         self.master.config = fakeConfig()
  573         serv = MyService(1, a=2, name="basic")
  574         yield serv.setServiceParent(self.master)
  575         yield self.master.startService()
  576         yield serv.reconfigServiceWithSibling(serv)
  577         return serv
  578 
  579     @defer.inlineCallbacks
  580     def testNominal(self):
  581         yield self.prepareService()
  582         self.assertEqual(
  583             self.master.namedServices["basic"].config, ((1,), dict(a=2)))
  584 
  585     @defer.inlineCallbacks
  586     def testConfigDict(self):
  587         serv = yield self.prepareService()
  588         self.assertEqual(serv.getConfigDict(), {
  589             'args': (1,),
  590             'class': 'buildbot.test.unit.test_util_service.MyService',
  591             'kwargs': {'a': 2},
  592             'name': 'basic'})
  593 
  594     def testNoName(self):
  595         with self.assertRaises(ValueError):
  596             MyService(1, a=2)
  597 
  598     def testChecksDone(self):
  599         with self.assertRaises(config.ConfigErrors):
  600             MyService(1, name="foo")
  601 
  602 
  603 class BuildbotServiceManager(unittest.TestCase):
  604 
  605     def setUp(self):
  606         self.master = makeFakeMaster()
  607 
  608     @defer.inlineCallbacks
  609     def prepareService(self):
  610         self.master.config = fakeConfig()
  611         serv = MyService(1, a=2, name="basic")
  612         self.master.config.services = {"basic": serv}
  613         self.manager = service.BuildbotServiceManager()
  614         yield self.manager.setServiceParent(self.master)
  615         yield self.master.startService()
  616         yield self.master.reconfigServiceWithBuildbotConfig(self.master.config)
  617         return serv
  618 
  619     @defer.inlineCallbacks
  620     def testNominal(self):
  621         yield self.prepareService()
  622         self.assertEqual(
  623             self.manager.namedServices["basic"].config, ((1,), dict(a=2)))
  624 
  625     @defer.inlineCallbacks
  626     def testReconfigNoChange(self):
  627         serv = yield self.prepareService()
  628         serv.config = None  # 'de-configure' the service
  629         # reconfigure with the same config
  630         serv2 = MyService(1, a=2, name="basic")
  631         self.master.config.services = {"basic": serv2}
  632 
  633         # reconfigure the master
  634         yield self.master.reconfigServiceWithBuildbotConfig(self.master.config)
  635         # the first service is still used
  636         self.assertIdentical(self.manager.namedServices["basic"], serv)
  637         # the second service is not used
  638         self.assertNotIdentical(self.manager.namedServices["basic"], serv2)
  639 
  640         # reconfigServiceWithConstructorArgs was not called
  641         self.assertEqual(serv.config, None)
  642 
  643     @defer.inlineCallbacks
  644     def testReconfigWithChanges(self):
  645         serv = yield self.prepareService()
  646         serv.config = None  # 'de-configure' the service
  647 
  648         # reconfigure with the different config
  649         serv2 = MyService(1, a=4, name="basic")
  650         self.master.config.services = {"basic": serv2}
  651 
  652         # reconfigure the master
  653         yield self.master.reconfigServiceWithBuildbotConfig(self.master.config)
  654         # the first service is still used
  655         self.assertIdentical(self.manager.namedServices["basic"], serv)
  656         # the second service is not used
  657         self.assertNotIdentical(self.manager.namedServices["basic"], serv2)
  658 
  659         # reconfigServiceWithConstructorArgs was called with new config
  660         self.assertEqual(serv.config, ((1,), dict(a=4)))
  661 
  662     def testNoName(self):
  663         with self.assertRaises(ValueError):
  664             MyService(1, a=2)
  665 
  666     def testChecksDone(self):
  667         with self.assertRaises(config.ConfigErrors):
  668             MyService(1, name="foo")
  669 
  670     @defer.inlineCallbacks
  671     def testReconfigWithNew(self):
  672         serv = yield self.prepareService()
  673 
  674         # reconfigure with the new service
  675         serv2 = MyService(1, a=4, name="basic2")
  676         self.master.config.services['basic2'] = serv2
  677 
  678         # the second service is not there yet
  679         self.assertIdentical(self.manager.namedServices.get("basic2"), None)
  680 
  681         # reconfigure the master
  682         yield self.master.reconfigServiceWithBuildbotConfig(self.master.config)
  683 
  684         # the first service is still used
  685         self.assertIdentical(self.manager.namedServices["basic"], serv)
  686         # the second service is created
  687         self.assertIdentical(self.manager.namedServices["basic2"], serv2)
  688 
  689         # reconfigServiceWithConstructorArgs was called with new config
  690         self.assertEqual(serv2.config, ((1,), dict(a=4)))
  691 
  692     @defer.inlineCallbacks
  693     def testReconfigWithDeleted(self):
  694         serv = yield self.prepareService()
  695         self.assertEqual(serv.running, True)
  696 
  697         # remove all
  698         self.master.config.services = {}
  699 
  700         # reconfigure the master
  701         yield self.master.reconfigServiceWithBuildbotConfig(self.master.config)
  702 
  703         # the first service is still used
  704         self.assertIdentical(self.manager.namedServices.get("basic"), None)
  705         self.assertEqual(serv.running, False)
  706 
  707     @defer.inlineCallbacks
  708     def testConfigDict(self):
  709         yield self.prepareService()
  710         self.assertEqual(self.manager.getConfigDict(), {
  711             'childs': [{
  712                 'args': (1,),
  713                 'class': 'buildbot.test.unit.test_util_service.MyService',
  714                 'kwargs': {'a': 2},
  715                 'name': 'basic'}],
  716             'name': 'services'})
  717 
  718     @defer.inlineCallbacks
  719     def testRenderSecrets(self):
  720         yield self.prepareService()
  721         service = self.manager.namedServices['basic']
  722         test = yield service.renderSecrets(Interpolate('test_string'))
  723         self.assertEqual(test, 'test_string')
  724 
  725     @defer.inlineCallbacks
  726     def testRenderSecrets2Args(self):
  727         yield self.prepareService()
  728         service = self.manager.namedServices['basic']
  729         test, test2 = yield service.renderSecrets(Interpolate('test_string'), 'ok_for_non_renderable')
  730         self.assertEqual(test, 'test_string')
  731         self.assertEqual(test2, 'ok_for_non_renderable')
  732 
  733     @defer.inlineCallbacks
  734     def testRenderSecretsWithTuple(self):
  735         yield self.prepareService()
  736         service = self.manager.namedServices['basic']
  737         test = yield service.renderSecrets(('user', Interpolate('test_string')))
  738         self.assertEqual(test, ('user', 'test_string'))
  739 
  740 
  741 class UnderTestSharedService(service.SharedService):
  742     def __init__(self, arg1=None):
  743         super().__init__()
  744 
  745 
  746 class UnderTestDependentService(service.AsyncService):
  747     @defer.inlineCallbacks
  748     def startService(self):
  749         self.dependent = yield UnderTestSharedService.getService(self.parent)
  750 
  751     def stopService(self):
  752         assert self.dependent.running
  753 
  754 
  755 class SharedService(unittest.SynchronousTestCase):
  756     def test_bad_constructor(self):
  757         parent = service.AsyncMultiService()
  758         self.failureResultOf(
  759             UnderTestSharedService.getService(parent, arg2="foo"))
  760 
  761     def test_creation(self):
  762         parent = service.AsyncMultiService()
  763         r = self.successResultOf(UnderTestSharedService.getService(parent))
  764         r2 = self.successResultOf(UnderTestSharedService.getService(parent))
  765         r3 = self.successResultOf(
  766             UnderTestSharedService.getService(parent, "arg1"))
  767         r4 = self.successResultOf(
  768             UnderTestSharedService.getService(parent, "arg1"))
  769         self.assertIdentical(r, r2)
  770         self.assertNotIdentical(r, r3)
  771         self.assertIdentical(r3, r4)
  772         self.assertEqual(len(list(iter(parent))), 2)
  773 
  774     def test_startup(self):
  775         """the service starts when parent starts and stop"""
  776         parent = service.AsyncMultiService()
  777         r = self.successResultOf(UnderTestSharedService.getService(parent))
  778         self.assertEqual(r.running, 0)
  779         self.successResultOf(parent.startService())
  780         self.assertEqual(r.running, 1)
  781         self.successResultOf(parent.stopService())
  782         self.assertEqual(r.running, 0)
  783 
  784     def test_already_started(self):
  785         """the service starts during the getService if parent already started"""
  786         parent = service.AsyncMultiService()
  787         self.successResultOf(parent.startService())
  788         r = self.successResultOf(UnderTestSharedService.getService(parent))
  789         self.assertEqual(r.running, 1)
  790         # then we stop the parent, and the shared service stops
  791         self.successResultOf(parent.stopService())
  792         self.assertEqual(r.running, 0)
  793 
  794     def test_already_stopped_last(self):
  795         parent = service.AsyncMultiService()
  796         o = UnderTestDependentService()
  797         o.setServiceParent(parent)
  798         self.successResultOf(parent.startService())
  799         self.successResultOf(parent.stopService())