PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/master/buildbot/test/unit/test_master.py

https://gitlab.com/murder187ss/buildbot
Python | 264 lines | 205 code | 39 blank | 20 comment | 1 complexity | 9d12ba8bcec6c858e9897070158c88b0 MD5 | raw 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. import os
  16. import signal
  17. import mock
  18. from twisted.internet import defer
  19. from twisted.internet import reactor
  20. from twisted.python import log
  21. from twisted.trial import unittest
  22. from buildbot import config
  23. from buildbot import master
  24. from buildbot import monkeypatches
  25. from buildbot.changes.changes import Change
  26. from buildbot.db import exceptions
  27. from buildbot.test.fake import fakedata
  28. from buildbot.test.fake import fakedb
  29. from buildbot.test.fake import fakemq
  30. from buildbot.test.util import dirs
  31. from buildbot.test.util import logging
  32. class OldTriggeringMethods(unittest.TestCase):
  33. def setUp(self):
  34. self.patch(master.BuildMaster, 'create_child_services',
  35. lambda self: None)
  36. self.master = master.BuildMaster(basedir=None)
  37. self.master.data = fakedata.FakeDataConnector(self.master, self)
  38. self.master.data.setServiceParent(self.master)
  39. self.db = self.master.db = fakedb.FakeDBConnector(self)
  40. self.db.setServiceParent(self.master)
  41. self.master.db.insertTestData([
  42. fakedb.Change(changeid=1, author='this is a test'),
  43. ])
  44. self.fake_Change = mock.Mock(name='fake_Change')
  45. def fromChdict(master, chdict):
  46. if chdict['author'] != 'this is a test':
  47. raise AssertionError("did not get expected chdict")
  48. return defer.succeed(self.fake_Change)
  49. self.patch(Change, 'fromChdict', staticmethod(fromChdict))
  50. def do_test_addChange_args(self, args=(), kwargs={}, exp_data_kwargs={}):
  51. # add default arguments
  52. default_data_kwargs = {
  53. 'author': None,
  54. 'branch': None,
  55. 'category': None,
  56. 'codebase': None,
  57. 'comments': None,
  58. 'files': None,
  59. 'project': '',
  60. 'properties': {},
  61. 'repository': '',
  62. 'revision': None,
  63. 'revlink': '',
  64. 'src': None,
  65. 'when_timestamp': None,
  66. }
  67. default_data_kwargs.update(exp_data_kwargs)
  68. exp_data_kwargs = default_data_kwargs
  69. d = self.master.addChange(*args, **kwargs)
  70. @d.addCallback
  71. def check(change):
  72. self.assertIdentical(change, self.fake_Change)
  73. self.assertEqual(self.master.data.updates.changesAdded,
  74. [exp_data_kwargs])
  75. return d
  76. def test_addChange_args_author(self):
  77. # who should come through as author
  78. return self.do_test_addChange_args(
  79. kwargs=dict(who='me'),
  80. exp_data_kwargs=dict(author='me'))
  81. def test_addChange_args_when(self):
  82. # when should come through as when_timestamp, as a datetime
  83. return self.do_test_addChange_args(
  84. kwargs=dict(when=892293875),
  85. exp_data_kwargs=dict(when_timestamp=892293875))
  86. def test_addChange_args_properties(self):
  87. # properties should not be qualified with a source
  88. return self.do_test_addChange_args(
  89. kwargs=dict(properties={'a': 'b'}),
  90. exp_data_kwargs=dict(properties={u'a': u'b'}))
  91. def test_addChange_args_properties_tuple(self):
  92. # properties should not be qualified with a source
  93. return self.do_test_addChange_args(
  94. kwargs=dict(properties={'a': ('b', 'Change')}),
  95. exp_data_kwargs=dict(properties={'a': ('b', 'Change')}))
  96. def test_addChange_args_positional(self):
  97. # master.addChange can take author, files, comments as positional
  98. # arguments
  99. return self.do_test_addChange_args(
  100. args=('me', ['a'], 'com'),
  101. exp_data_kwargs=dict(author='me', files=['a'], comments='com'))
  102. class StartupAndReconfig(dirs.DirsMixin, logging.LoggingMixin, unittest.TestCase):
  103. def setUp(self):
  104. self.setUpLogging()
  105. self.basedir = os.path.abspath('basedir')
  106. d = self.setUpDirs(self.basedir)
  107. @d.addCallback
  108. def make_master(_):
  109. # don't create child services
  110. self.patch(master.BuildMaster, 'create_child_services',
  111. lambda self: None)
  112. # patch out a few other annoying things the master likes to do
  113. self.patch(monkeypatches, 'patch_all', lambda: None)
  114. self.patch(signal, 'signal', lambda sig, hdlr: None)
  115. self.patch(master, 'Status', lambda master: mock.Mock()) # XXX temporary
  116. self.patch(config.MasterConfig, 'loadConfig',
  117. classmethod(lambda cls, b, f: cls()))
  118. self.reactor = self.make_reactor()
  119. self.master = master.BuildMaster(self.basedir, reactor=self.reactor)
  120. self.db = self.master.db = fakedb.FakeDBConnector(self)
  121. self.db.setServiceParent(self.master)
  122. self.mq = self.master.mq = fakemq.FakeMQConnector(self)
  123. self.mq.setServiceParent(self.master)
  124. self.data = self.master.data = fakedata.FakeDataConnector(self.master, self)
  125. self.data.setServiceParent(self.master)
  126. return d
  127. def tearDown(self):
  128. return self.tearDownDirs()
  129. def make_reactor(self):
  130. r = mock.Mock()
  131. r.callWhenRunning = reactor.callWhenRunning
  132. r.getThreadPool = reactor.getThreadPool
  133. r.callFromThread = reactor.callFromThread
  134. return r
  135. def patch_loadConfig_fail(self):
  136. @classmethod
  137. def loadConfig(cls, b, f):
  138. config.error('oh noes')
  139. self.patch(config.MasterConfig, 'loadConfig', loadConfig)
  140. # tests
  141. def test_startup_bad_config(self):
  142. self.patch_loadConfig_fail()
  143. d = self.master.startService()
  144. @d.addCallback
  145. def check(_):
  146. self.reactor.stop.assert_called_with()
  147. self.assertLogged("oh noes")
  148. return d
  149. def test_startup_db_not_ready(self):
  150. def db_setup():
  151. log.msg("GOT HERE")
  152. raise exceptions.DatabaseNotReadyError()
  153. self.db.setup = db_setup
  154. d = self.master.startService()
  155. @d.addCallback
  156. def check(_):
  157. self.reactor.stop.assert_called_with()
  158. self.assertLogged("GOT HERE")
  159. return d
  160. def test_startup_error(self):
  161. def db_setup():
  162. raise RuntimeError("oh noes")
  163. self.db.setup = db_setup
  164. d = self.master.startService()
  165. @d.addCallback
  166. def check(_):
  167. self.reactor.stop.assert_called_with()
  168. self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1)
  169. return d
  170. def test_startup_ok(self):
  171. d = self.master.startService()
  172. @d.addCallback
  173. def check_started(_):
  174. self.assertTrue(self.master.data.updates.thisMasterActive)
  175. d.addCallback(lambda _: self.master.stopService())
  176. @d.addCallback
  177. def check(_):
  178. self.failIf(self.reactor.stop.called)
  179. self.assertLogged("BuildMaster is running")
  180. # check started/stopped messages
  181. self.assertFalse(self.master.data.updates.thisMasterActive)
  182. return d
  183. @defer.inlineCallbacks
  184. def test_reconfig(self):
  185. self.master.reconfigServiceWithBuildbotConfig = mock.Mock(
  186. side_effect=lambda n: defer.succeed(None))
  187. self.master.masterHeartbeatService = mock.Mock()
  188. yield self.master.startService()
  189. yield self.master.reconfig()
  190. yield self.master.stopService()
  191. self.master.reconfigServiceWithBuildbotConfig.assert_called_with(mock.ANY)
  192. @defer.inlineCallbacks
  193. def test_reconfig_bad_config(self):
  194. self.master.reconfigService = mock.Mock(
  195. side_effect=lambda n: defer.succeed(None))
  196. self.master.masterHeartbeatService = mock.Mock()
  197. yield self.master.startService()
  198. # reset, since startService called reconfigService
  199. self.master.reconfigService.reset_mock()
  200. # reconfig, with a failure
  201. self.patch_loadConfig_fail()
  202. yield self.master.reconfig()
  203. self.master.stopService()
  204. self.assertLogged("reconfig aborted without")
  205. self.failIf(self.master.reconfigService.called)
  206. @defer.inlineCallbacks
  207. def test_reconfigService_db_url_changed(self):
  208. old = self.master.config = config.MasterConfig()
  209. old.db['db_url'] = 'aaaa'
  210. yield self.master.reconfigServiceWithBuildbotConfig(old)
  211. new = config.MasterConfig()
  212. new.db['db_url'] = 'bbbb'
  213. self.assertRaises(config.ConfigErrors, lambda:
  214. self.master.reconfigServiceWithBuildbotConfig(new))