Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: third_party/buildbot_7_12/buildbot/test/test_config.py

Issue 12207158: Bye bye buildbot 0.7.12. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: buildbot.test.test_config -*-
2
3 import os, warnings, exceptions
4
5 from twisted.trial import unittest
6 from twisted.python import failure
7 from twisted.internet import defer
8
9 from buildbot.master import BuildMaster
10 from buildbot import scheduler
11 from twisted.application import service, internet
12 from twisted.spread import pb
13 from twisted.web.server import Site
14 from twisted.web.distrib import ResourcePublisher
15 from buildbot.process.builder import Builder
16 from buildbot.process.factory import BasicBuildFactory, ArgumentsInTheWrongPlace
17 from buildbot.changes.pb import PBChangeSource
18 from buildbot.changes.mail import SyncmailMaildirSource
19 from buildbot.steps.source import CVS, Darcs
20 from buildbot.steps.shell import Compile, Test, ShellCommand
21 from buildbot.status import base
22 from buildbot.steps import dummy, maxq, python, python_twisted, shell, \
23 source, transfer
24 words = None
25 try:
26 from buildbot.status import words
27 except ImportError:
28 pass
29
30 emptyCfg = \
31 """
32 from buildbot.buildslave import BuildSlave
33 BuildmasterConfig = c = {}
34 c['slaves'] = []
35 c['schedulers'] = []
36 c['builders'] = []
37 c['slavePortnum'] = 9999
38 c['projectName'] = 'dummy project'
39 c['projectURL'] = 'http://dummy.example.com'
40 c['buildbotURL'] = 'http://dummy.example.com/buildbot'
41 """
42
43 buildersCfg = \
44 """
45 from buildbot.process.factory import BasicBuildFactory
46 from buildbot.buildslave import BuildSlave
47 BuildmasterConfig = c = {}
48 c['slaves'] = [BuildSlave('bot1', 'pw1')]
49 c['schedulers'] = []
50 c['slavePortnum'] = 9999
51 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
52 c['builders'] = [{'name':'builder1', 'slavename':'bot1',
53 'builddir':'workdir', 'factory':f1}]
54 """
55
56 buildersCfg2 = buildersCfg + \
57 """
58 f1 = BasicBuildFactory('cvsroot', 'cvsmodule2')
59 c['builders'] = [{'name':'builder1', 'slavename':'bot1',
60 'builddir':'workdir', 'factory':f1}]
61 """
62
63 buildersCfg3 = buildersCfg2 + \
64 """
65 c['builders'].append({'name': 'builder2', 'slavename': 'bot1',
66 'builddir': 'workdir2', 'factory': f1 })
67 """
68
69 buildersCfg4 = buildersCfg2 + \
70 """
71 c['builders'] = [{ 'name': 'builder1', 'slavename': 'bot1',
72 'builddir': 'newworkdir', 'factory': f1 },
73 { 'name': 'builder2', 'slavename': 'bot1',
74 'builddir': 'workdir2', 'factory': f1 }]
75 """
76
77 buildersCfg5 = buildersCfg2 + \
78 """
79 from buildbot.config import BuilderConfig
80 c['builders'] = [
81 BuilderConfig(
82 name = 'builder1',
83 slavename = 'bot1',
84 builddir = 'newworkdir',
85 factory = f1),
86 BuilderConfig(
87 name = 'builder2',
88 slavename = 'bot1',
89 builddir = 'workdir2',
90 factory = f1)
91 ]
92 """
93
94
95 wpCfg1 = buildersCfg + \
96 """
97 from buildbot.steps import shell
98 from buildbot.config import BuilderConfig
99 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
100 f1.addStep(shell.ShellCommand, command=[shell.WithProperties('echo')])
101 c['builders'] = [
102 BuilderConfig(name='builder1', slavename='bot1',
103 builddir='workdir1', factory=f1)
104 ]
105 """
106
107 wpCfg2 = buildersCfg + \
108 """
109 from buildbot.steps import shell
110 from buildbot.config import BuilderConfig
111 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
112 f1.addStep(shell.ShellCommand,
113 command=[shell.WithProperties('echo %s', 'revision')])
114 c['builders'] = [
115 BuilderConfig(name='builder1', slavename='bot1',
116 builddir='workdir1', factory=f1)
117 ]
118 """
119
120
121
122 ircCfg1 = emptyCfg + \
123 """
124 from buildbot.status import words
125 c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted'])]
126 """
127
128 ircCfg2 = emptyCfg + \
129 """
130 from buildbot.status import words
131 c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted']),
132 words.IRC('irc.example.com', 'otherbot', ['chan1', 'chan2'])]
133 """
134
135 ircCfg3 = emptyCfg + \
136 """
137 from buildbot.status import words
138 c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['knotted'])]
139 """
140
141 webCfg1 = emptyCfg + \
142 """
143 from buildbot.status import html
144 c['status'] = [html.Waterfall(http_port=9980)]
145 """
146
147 webCfg2 = emptyCfg + \
148 """
149 from buildbot.status import html
150 c['status'] = [html.Waterfall(http_port=9981)]
151 """
152
153 webCfg3 = emptyCfg + \
154 """
155 from buildbot.status import html
156 c['status'] = [html.Waterfall(http_port='tcp:9981:interface=127.0.0.1')]
157 """
158
159 webNameCfg1 = emptyCfg + \
160 """
161 from buildbot.status import html
162 c['status'] = [html.Waterfall(distrib_port='~/.twistd-web-pb')]
163 """
164
165 webNameCfg2 = emptyCfg + \
166 """
167 from buildbot.status import html
168 c['status'] = [html.Waterfall(distrib_port='./bar.socket')]
169 """
170
171 debugPasswordCfg = emptyCfg + \
172 """
173 c['debugPassword'] = 'sekrit'
174 """
175
176 interlockCfgBad = \
177 """
178 from buildbot.process.factory import BasicBuildFactory
179 from buildbot.buildslave import BuildSlave
180 from buildbot.config import BuilderConfig
181 c = {}
182 c['slaves'] = [BuildSlave('bot1', 'pw1')]
183 c['schedulers'] = []
184 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
185 c['builders'] = [
186 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
187 BuilderConfig(name='builder2', slavename='bot1', factory=f1),
188 ]
189 # interlocks have been removed
190 c['interlocks'] = [('lock1', ['builder1'], ['builder2', 'builder3']),
191 ]
192 c['slavePortnum'] = 9999
193 BuildmasterConfig = c
194 """
195
196 lockCfgBad1 = \
197 """
198 from buildbot.steps.dummy import Dummy
199 from buildbot.process.factory import BuildFactory, s
200 from buildbot.locks import MasterLock
201 from buildbot.buildslave import BuildSlave
202 from buildbot.config import BuilderConfig
203 c = {}
204 c['slaves'] = [BuildSlave('bot1', 'pw1')]
205 c['schedulers'] = []
206 l1 = MasterLock('lock1')
207 l2 = MasterLock('lock1') # duplicate lock name
208 f1 = BuildFactory([s(Dummy, locks=[])])
209 c['builders'] = [
210 BuilderConfig(name='builder1', slavename='bot1', factory=f1,
211 locks=[l1, l2]),
212 BuilderConfig(name='builder2', slavename='bot1', factory=f1),
213 ]
214 c['slavePortnum'] = 9999
215 BuildmasterConfig = c
216 """
217
218 lockCfgBad2 = \
219 """
220 from buildbot.steps.dummy import Dummy
221 from buildbot.process.factory import BuildFactory, s
222 from buildbot.locks import MasterLock, SlaveLock
223 from buildbot.buildslave import BuildSlave
224 from buildbot.config import BuilderConfig
225 c = {}
226 c['slaves'] = [BuildSlave('bot1', 'pw1')]
227 c['schedulers'] = []
228 l1 = MasterLock('lock1')
229 l2 = SlaveLock('lock1') # duplicate lock name
230 f1 = BuildFactory([s(Dummy, locks=[])])
231 c['builders'] = [
232 BuilderConfig(name='builder1', slavename='bot1', factory=f1,
233 locks=[l1, l2]),
234 BuilderConfig(name='builder2', slavename='bot1', factory=f1),
235 ]
236 c['slavePortnum'] = 9999
237 BuildmasterConfig = c
238 """
239
240 lockCfgBad3 = \
241 """
242 from buildbot.steps.dummy import Dummy
243 from buildbot.process.factory import BuildFactory, s
244 from buildbot.locks import MasterLock
245 from buildbot.buildslave import BuildSlave
246 c = {}
247 c['slaves'] = [BuildSlave('bot1', 'pw1')]
248 c['schedulers'] = []
249 l1 = MasterLock('lock1')
250 l2 = MasterLock('lock1') # duplicate lock name
251 f1 = BuildFactory([s(Dummy, locks=[l2])])
252 f2 = BuildFactory([s(Dummy)])
253 c['builders'] = [
254 { 'name': 'builder1', 'slavename': 'bot1',
255 'builddir': 'workdir', 'factory': f2, 'locks': [l1] },
256 { 'name': 'builder2', 'slavename': 'bot1',
257 'builddir': 'workdir2', 'factory': f1 },
258 ]
259 c['slavePortnum'] = 9999
260 BuildmasterConfig = c
261 """
262
263 lockCfg1a = \
264 """
265 from buildbot.process.factory import BasicBuildFactory
266 from buildbot.locks import MasterLock
267 from buildbot.buildslave import BuildSlave
268 from buildbot.config import BuilderConfig
269 c = {}
270 c['slaves'] = [BuildSlave('bot1', 'pw1')]
271 c['schedulers'] = []
272 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
273 l1 = MasterLock('lock1')
274 l2 = MasterLock('lock2')
275 c['builders'] = [
276 BuilderConfig(name='builder1', slavename='bot1', factory=f1,
277 locks=[l1, l2]),
278 BuilderConfig(name='builder2', slavename='bot1', factory=f1),
279 ]
280 c['slavePortnum'] = 9999
281 BuildmasterConfig = c
282 """
283
284 lockCfg1b = \
285 """
286 from buildbot.process.factory import BasicBuildFactory
287 from buildbot.locks import MasterLock
288 from buildbot.buildslave import BuildSlave
289 from buildbot.config import BuilderConfig
290 c = {}
291 c['slaves'] = [BuildSlave('bot1', 'pw1')]
292 c['schedulers'] = []
293 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
294 l1 = MasterLock('lock1')
295 l2 = MasterLock('lock2')
296 c['builders'] = [
297 BuilderConfig(name='builder1', slavename='bot1', factory=f1, locks=[l1]),
298 BuilderConfig(name='builder2', slavename='bot1', factory=f1),
299 ]
300 c['slavePortnum'] = 9999
301 BuildmasterConfig = c
302 """
303
304 # test out step Locks
305 lockCfg2a = \
306 """
307 from buildbot.steps.dummy import Dummy
308 from buildbot.process.factory import BuildFactory, s
309 from buildbot.locks import MasterLock
310 from buildbot.buildslave import BuildSlave
311 from buildbot.config import BuilderConfig
312 c = {}
313 c['slaves'] = [BuildSlave('bot1', 'pw1')]
314 c['schedulers'] = []
315 l1 = MasterLock('lock1')
316 l2 = MasterLock('lock2')
317 f1 = BuildFactory([s(Dummy, locks=[l1,l2])])
318 f2 = BuildFactory([s(Dummy)])
319
320 c['builders'] = [
321 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
322 BuilderConfig(name='builder2', slavename='bot1', factory=f2),
323 ]
324 c['slavePortnum'] = 9999
325 BuildmasterConfig = c
326 """
327
328 lockCfg2b = \
329 """
330 from buildbot.steps.dummy import Dummy
331 from buildbot.process.factory import BuildFactory, s
332 from buildbot.locks import MasterLock
333 from buildbot.buildslave import BuildSlave
334 from buildbot.config import BuilderConfig
335 c = {}
336 c['slaves'] = [BuildSlave('bot1', 'pw1')]
337 c['schedulers'] = []
338 l1 = MasterLock('lock1')
339 l2 = MasterLock('lock2')
340 f1 = BuildFactory([s(Dummy, locks=[l1])])
341 f2 = BuildFactory([s(Dummy)])
342
343 c['builders'] = [
344 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
345 BuilderConfig(name='builder2', slavename='bot1', factory=f2),
346 ]
347 c['slavePortnum'] = 9999
348 BuildmasterConfig = c
349 """
350
351 lockCfg2c = \
352 """
353 from buildbot.steps.dummy import Dummy
354 from buildbot.process.factory import BuildFactory, s
355 from buildbot.locks import MasterLock
356 from buildbot.buildslave import BuildSlave
357 from buildbot.config import BuilderConfig
358 c = {}
359 c['slaves'] = [BuildSlave('bot1', 'pw1')]
360 c['schedulers'] = []
361 l1 = MasterLock('lock1')
362 l2 = MasterLock('lock2')
363 f1 = BuildFactory([s(Dummy)])
364 f2 = BuildFactory([s(Dummy)])
365
366 c['builders'] = [
367 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
368 BuilderConfig(name='builder2', slavename='bot1', factory=f2),
369 ]
370 c['slavePortnum'] = 9999
371 BuildmasterConfig = c
372 """
373
374 schedulersCfg = \
375 """
376 from buildbot.scheduler import Scheduler, Dependent
377 from buildbot.process.factory import BasicBuildFactory
378 from buildbot.buildslave import BuildSlave
379 from buildbot.config import BuilderConfig
380 c = {}
381 c['slaves'] = [BuildSlave('bot1', 'pw1')]
382 f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
383 b1 = BuilderConfig(name='builder1', slavename='bot1', factory=f1)
384 c['builders'] = [b1]
385 c['schedulers'] = [Scheduler('full', None, 60, ['builder1'])]
386 c['slavePortnum'] = 9999
387 c['projectName'] = 'dummy project'
388 c['projectURL'] = 'http://dummy.example.com'
389 c['buildbotURL'] = 'http://dummy.example.com/buildbot'
390 BuildmasterConfig = c
391 """
392
393 class ConfigTest(unittest.TestCase):
394 def setUp(self):
395 # this class generates several deprecation warnings, which the user
396 # doesn't need to see.
397 warnings.simplefilter('ignore', exceptions.DeprecationWarning)
398 self.buildmaster = BuildMaster(".")
399
400 def failUnlessListsEquivalent(self, list1, list2):
401 l1 = list1[:]
402 l1.sort()
403 l2 = list2[:]
404 l2.sort()
405 self.failUnlessEqual(l1, l2)
406
407 def servers(self, s, types):
408 # perform a recursive search of s.services, looking for instances of
409 # twisted.application.internet.TCPServer, then extract their .args
410 # values to find the TCP ports they want to listen on
411 for child in s:
412 if service.IServiceCollection.providedBy(child):
413 for gc in self.servers(child, types):
414 yield gc
415 if isinstance(child, types):
416 yield child
417
418 def TCPports(self, s):
419 return list(self.servers(s, internet.TCPServer))
420 def UNIXports(self, s):
421 return list(self.servers(s, internet.UNIXServer))
422 def TCPclients(self, s):
423 return list(self.servers(s, internet.TCPClient))
424
425 def checkPorts(self, svc, expected):
426 """Verify that the TCPServer and UNIXServer children of the given
427 service have the expected portnum/pathname and factory classes. As a
428 side-effect, return a list of servers in the same order as the
429 'expected' list. This can be used to verify properties of the
430 factories contained therein."""
431
432 expTCP = [e for e in expected if type(e[0]) == int]
433 expUNIX = [e for e in expected if type(e[0]) == str]
434 haveTCP = [(p.args[0], p.args[1].__class__)
435 for p in self.TCPports(svc)]
436 haveUNIX = [(p.args[0], p.args[1].__class__)
437 for p in self.UNIXports(svc)]
438 self.failUnlessListsEquivalent(expTCP, haveTCP)
439 self.failUnlessListsEquivalent(expUNIX, haveUNIX)
440 ret = []
441 for e in expected:
442 for have in self.TCPports(svc) + self.UNIXports(svc):
443 if have.args[0] == e[0]:
444 ret.append(have)
445 continue
446 assert(len(ret) == len(expected))
447 return ret
448
449 def testEmpty(self):
450 self.failUnlessRaises(KeyError, self.buildmaster.loadConfig, "")
451
452 def testSimple(self):
453 # covers slavePortnum, base checker passwords
454 master = self.buildmaster
455 master.loadChanges()
456
457 master.loadConfig(emptyCfg)
458 # note: this doesn't actually start listening, because the app
459 # hasn't been started running
460 self.failUnlessEqual(master.slavePortnum, "tcp:9999")
461 self.checkPorts(master, [(9999, pb.PBServerFactory)])
462 self.failUnlessEqual(list(master.change_svc), [])
463 self.failUnlessEqual(master.botmaster.builders, {})
464 self.failUnlessEqual(master.checker.users,
465 {"change": "changepw"})
466 self.failUnlessEqual(master.projectName, "dummy project")
467 self.failUnlessEqual(master.projectURL, "http://dummy.example.com")
468 self.failUnlessEqual(master.buildbotURL,
469 "http://dummy.example.com/buildbot")
470
471 def testSlavePortnum(self):
472 master = self.buildmaster
473 master.loadChanges()
474
475 master.loadConfig(emptyCfg)
476 self.failUnlessEqual(master.slavePortnum, "tcp:9999")
477 ports = self.checkPorts(master, [(9999, pb.PBServerFactory)])
478 p = ports[0]
479
480 master.loadConfig(emptyCfg)
481 self.failUnlessEqual(master.slavePortnum, "tcp:9999")
482 ports = self.checkPorts(master, [(9999, pb.PBServerFactory)])
483 self.failUnlessIdentical(p, ports[0],
484 "the slave port was changed even " + \
485 "though the configuration was not")
486
487 master.loadConfig(emptyCfg + "c['slavePortnum'] = 9000\n")
488 self.failUnlessEqual(master.slavePortnum, "tcp:9000")
489 ports = self.checkPorts(master, [(9000, pb.PBServerFactory)])
490 self.failIf(p is ports[0],
491 "slave port was unchanged but configuration was changed")
492
493 def testSlaves(self):
494 master = self.buildmaster
495 master.loadChanges()
496 master.loadConfig(emptyCfg)
497 self.failUnlessEqual(master.botmaster.builders, {})
498 self.failUnlessEqual(master.checker.users,
499 {"change": "changepw"})
500 # 'botsCfg' is testing backwards compatibility, for 0.7.5 config
501 # files that have not yet been updated to 0.7.6 . This compatibility
502 # (and this test) is scheduled for removal in 0.8.0 .
503 botsCfg = (emptyCfg +
504 "c['bots'] = [('bot1', 'pw1'), ('bot2', 'pw2')]\n")
505 master.loadConfig(botsCfg)
506 self.failUnlessEqual(master.checker.users,
507 {"change": "changepw",
508 "bot1": "pw1",
509 "bot2": "pw2"})
510 master.loadConfig(botsCfg)
511 self.failUnlessEqual(master.checker.users,
512 {"change": "changepw",
513 "bot1": "pw1",
514 "bot2": "pw2"})
515 master.loadConfig(emptyCfg)
516 self.failUnlessEqual(master.checker.users,
517 {"change": "changepw"})
518 slavesCfg = (emptyCfg +
519 "from buildbot.buildslave import BuildSlave\n"
520 "c['slaves'] = [BuildSlave('bot1','pw1'), "
521 "BuildSlave('bot2','pw2')]\n")
522 master.loadConfig(slavesCfg)
523 self.failUnlessEqual(master.checker.users,
524 {"change": "changepw",
525 "bot1": "pw1",
526 "bot2": "pw2"})
527
528
529 def testChangeSource(self):
530 master = self.buildmaster
531 master.loadChanges()
532 master.loadConfig(emptyCfg)
533 self.failUnlessEqual(list(master.change_svc), [])
534
535 sourcesCfg = emptyCfg + \
536 """
537 from buildbot.changes.pb import PBChangeSource
538 c['change_source'] = PBChangeSource()
539 """
540
541 d = master.loadConfig(sourcesCfg)
542 def _check1(res):
543 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
544 s1 = list(self.buildmaster.change_svc)[0]
545 self.failUnless(isinstance(s1, PBChangeSource))
546 self.failUnlessEqual(s1, list(self.buildmaster.change_svc)[0])
547 self.failUnless(s1.parent)
548
549 # verify that unchanged sources are not interrupted
550 d1 = self.buildmaster.loadConfig(sourcesCfg)
551
552 def _check2(res):
553 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
554 s2 = list(self.buildmaster.change_svc)[0]
555 self.failUnlessIdentical(s1, s2)
556 self.failUnless(s1.parent)
557 d1.addCallback(_check2)
558 return d1
559 d.addCallback(_check1)
560
561 # make sure we can get rid of the sources too
562 d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
563
564 def _check3(res):
565 self.failUnlessEqual(list(self.buildmaster.change_svc), [])
566 d.addCallback(_check3)
567
568 return d
569
570 def testChangeSources(self):
571 # make sure we can accept a list
572 master = self.buildmaster
573 master.loadChanges()
574 master.loadConfig(emptyCfg)
575 self.failUnlessEqual(list(master.change_svc), [])
576
577 sourcesCfg = emptyCfg + \
578 """
579 from buildbot.changes.pb import PBChangeSource
580 from buildbot.changes.mail import SyncmailMaildirSource
581 c['change_source'] = [PBChangeSource(),
582 SyncmailMaildirSource('.'),
583 ]
584 """
585
586 d = master.loadConfig(sourcesCfg)
587 def _check1(res):
588 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 2)
589 s1,s2 = list(self.buildmaster.change_svc)
590 if isinstance(s2, PBChangeSource):
591 s1,s2 = s2,s1
592 self.failUnless(isinstance(s1, PBChangeSource))
593 self.failUnless(s1.parent)
594 self.failUnless(isinstance(s2, SyncmailMaildirSource))
595 self.failUnless(s2.parent)
596 d.addCallback(_check1)
597 return d
598
599 def testSources(self):
600 # test backwards compatibility. c['sources'] is deprecated.
601 master = self.buildmaster
602 master.loadChanges()
603 master.loadConfig(emptyCfg)
604 self.failUnlessEqual(list(master.change_svc), [])
605
606 sourcesCfg = emptyCfg + \
607 """
608 from buildbot.changes.pb import PBChangeSource
609 c['sources'] = [PBChangeSource()]
610 """
611
612 d = master.loadConfig(sourcesCfg)
613 def _check1(res):
614 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
615 s1 = list(self.buildmaster.change_svc)[0]
616 self.failUnless(isinstance(s1, PBChangeSource))
617 self.failUnless(s1.parent)
618 d.addCallback(_check1)
619 return d
620
621 def shouldBeFailure(self, res, *expected):
622 self.failUnless(isinstance(res, failure.Failure),
623 "we expected this to fail, not produce %s" % (res,))
624 res.trap(*expected)
625 return None # all is good
626
627 def testSchedulerErrors(self):
628 master = self.buildmaster
629 master.loadChanges()
630 master.loadConfig(emptyCfg)
631 self.failUnlessEqual(master.allSchedulers(), [])
632
633 def _shouldBeFailure(res, hint=None):
634 self.shouldBeFailure(res, AssertionError, ValueError)
635 if hint:
636 self.failUnless(str(res).find(hint) != -1)
637
638 def _loadConfig(res, newcfg):
639 return self.buildmaster.loadConfig(newcfg)
640 d = defer.succeed(None)
641
642 # c['schedulers'] must be a list
643 badcfg = schedulersCfg + \
644 """
645 c['schedulers'] = Scheduler('full', None, 60, ['builder1'])
646 """
647 d.addCallback(_loadConfig, badcfg)
648 d.addBoth(_shouldBeFailure,
649 "c['schedulers'] must be a list of Scheduler instances")
650
651 # c['schedulers'] must be a list of IScheduler objects
652 badcfg = schedulersCfg + \
653 """
654 c['schedulers'] = ['oops', 'problem']
655 """
656 d.addCallback(_loadConfig, badcfg)
657 d.addBoth(_shouldBeFailure,
658 "c['schedulers'] must be a list of Scheduler instances")
659
660 # c['schedulers'] must point at real builders
661 badcfg = schedulersCfg + \
662 """
663 c['schedulers'] = [Scheduler('full', None, 60, ['builder-bogus'])]
664 """
665 d.addCallback(_loadConfig, badcfg)
666 d.addBoth(_shouldBeFailure, "uses unknown builder")
667
668 # builderNames= must be a list
669 badcfg = schedulersCfg + \
670 """
671 c['schedulers'] = [Scheduler('full', None, 60, 'builder1')]
672 """
673 d.addCallback(_loadConfig, badcfg)
674 d.addBoth(_shouldBeFailure,
675 "must be a list of Builder description names")
676
677 # builderNames= must be a list of strings, not dicts
678 badcfg = schedulersCfg + \
679 """
680 c['schedulers'] = [Scheduler('full', None, 60, [b1])]
681 """
682 d.addCallback(_loadConfig, badcfg)
683 d.addBoth(_shouldBeFailure,
684 "must be a list of Builder description names")
685
686 # builderNames= must be a list of strings, not a dict
687 badcfg = schedulersCfg + \
688 """
689 c['schedulers'] = [Scheduler('full', None, 60, b1)]
690 """
691 d.addCallback(_loadConfig, badcfg)
692 d.addBoth(_shouldBeFailure,
693 "must be a list of Builder description names")
694
695 # each Scheduler must have a unique name
696 badcfg = schedulersCfg + \
697 """
698 c['schedulers'] = [Scheduler('dup', None, 60, []),
699 Scheduler('dup', None, 60, [])]
700 """
701 d.addCallback(_loadConfig, badcfg)
702 d.addBoth(_shouldBeFailure, "Schedulers must have unique names")
703
704 return d
705
706 def testSchedulers(self):
707 master = self.buildmaster
708 master.loadChanges()
709 master.loadConfig(emptyCfg)
710 self.failUnlessEqual(master.allSchedulers(), [])
711
712 d = self.buildmaster.loadConfig(schedulersCfg)
713 d.addCallback(self._testSchedulers_1)
714 return d
715
716 def _testSchedulers_1(self, res):
717 sch = self.buildmaster.allSchedulers()
718 self.failUnlessEqual(len(sch), 1)
719 s = sch[0]
720 self.failUnless(isinstance(s, scheduler.Scheduler))
721 self.failUnlessEqual(s.name, "full")
722 self.failUnlessEqual(s.branch, None)
723 self.failUnlessEqual(s.treeStableTimer, 60)
724 self.failUnlessEqual(s.builderNames, ['builder1'])
725
726 newcfg = schedulersCfg + \
727 """
728 s1 = Scheduler('full', None, 60, ['builder1'])
729 c['schedulers'] = [s1, Dependent('downstream', s1, ['builder1'])]
730 """
731 d = self.buildmaster.loadConfig(newcfg)
732 d.addCallback(self._testSchedulers_2, newcfg)
733 return d
734 def _testSchedulers_2(self, res, newcfg):
735 sch = self.buildmaster.allSchedulers()
736 self.failUnlessEqual(len(sch), 2)
737 s = sch[0]
738 self.failUnless(isinstance(s, scheduler.Scheduler))
739 s = sch[1]
740 self.failUnless(isinstance(s, scheduler.Dependent))
741 self.failUnlessEqual(s.name, "downstream")
742 self.failUnlessEqual(s.builderNames, ['builder1'])
743
744 # reloading the same config file should leave the schedulers in place
745 d = self.buildmaster.loadConfig(newcfg)
746 d.addCallback(self._testSchedulers_3, sch)
747 return d
748 def _testSchedulers_3(self, res, sch1):
749 sch2 = self.buildmaster.allSchedulers()
750 self.failUnlessEqual(len(sch2), 2)
751 sch1.sort()
752 sch2.sort()
753 self.failUnlessEqual(sch1, sch2)
754 self.failUnlessIdentical(sch1[0], sch2[0])
755 self.failUnlessIdentical(sch1[1], sch2[1])
756 self.failUnlessIdentical(sch1[0].parent, self.buildmaster)
757 self.failUnlessIdentical(sch1[1].parent, self.buildmaster)
758
759
760
761 def testBuilders(self):
762 master = self.buildmaster
763 master.loadConfig(emptyCfg)
764 self.failUnlessEqual(master.botmaster.builders, {})
765
766 master.loadConfig(buildersCfg)
767 self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
768 self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
769 b = master.botmaster.builders["builder1"]
770 self.failUnless(isinstance(b, Builder))
771 self.failUnlessEqual(b.name, "builder1")
772 self.failUnlessEqual(b.slavenames, ["bot1"])
773 self.failUnlessEqual(b.builddir, "workdir")
774 f1 = b.buildFactory
775 self.failUnless(isinstance(f1, BasicBuildFactory))
776 steps = f1.steps
777 self.failUnlessEqual(len(steps), 3)
778 self.failUnlessEqual(steps[0], (CVS,
779 {'cvsroot': 'cvsroot',
780 'cvsmodule': 'cvsmodule',
781 'mode': 'clobber'}))
782 self.failUnlessEqual(steps[1], (Compile,
783 {'command': 'make all'}))
784 self.failUnlessEqual(steps[2], (Test,
785 {'command': 'make check'}))
786
787
788 # make sure a reload of the same data doesn't interrupt the Builder
789 master.loadConfig(buildersCfg)
790 self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
791 self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
792 b2 = master.botmaster.builders["builder1"]
793 self.failUnlessIdentical(b, b2)
794 # TODO: test that the BuilderStatus object doesn't change
795 #statusbag2 = master.client_svc.statusbags["builder1"]
796 #self.failUnlessIdentical(statusbag, statusbag2)
797
798 # but changing something should result in a new Builder
799 master.loadConfig(buildersCfg2)
800 self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
801 self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
802 b3 = master.botmaster.builders["builder1"]
803 self.failIf(b is b3)
804 # the statusbag remains the same TODO
805 #statusbag3 = master.client_svc.statusbags["builder1"]
806 #self.failUnlessIdentical(statusbag, statusbag3)
807
808 # adding new builder
809 master.loadConfig(buildersCfg3)
810 self.failUnlessEqual(master.botmaster.builderNames, ["builder1",
811 "builder2"])
812 self.failUnlessListsEquivalent(master.botmaster.builders.keys(),
813 ["builder1", "builder2"])
814 b4 = master.botmaster.builders["builder1"]
815 self.failUnlessIdentical(b3, b4)
816
817 # changing first builder should leave it at the same place in the list
818 master.loadConfig(buildersCfg4)
819 self.failUnlessEqual(master.botmaster.builderNames, ["builder1",
820 "builder2"])
821 self.failUnlessListsEquivalent(master.botmaster.builders.keys(),
822 ["builder1", "builder2"])
823 b5 = master.botmaster.builders["builder1"]
824 self.failIf(b4 is b5)
825
826 master.loadConfig(buildersCfg5)
827 self.failUnlessEqual(master.botmaster.builderNames, ["builder1",
828 "builder2"])
829 self.failUnlessListsEquivalent(master.botmaster.builders.keys(),
830 ["builder1", "builder2"])
831 b5 = master.botmaster.builders["builder1"]
832
833 # and removing it should make the Builder go away
834 master.loadConfig(emptyCfg)
835 self.failUnlessEqual(master.botmaster.builderNames, [])
836 self.failUnlessEqual(master.botmaster.builders, {})
837 #self.failUnlessEqual(master.client_svc.statusbags, {}) # TODO
838
839 def testWithProperties(self):
840 master = self.buildmaster
841 master.loadConfig(wpCfg1)
842 self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
843 self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
844 b1 = master.botmaster.builders["builder1"]
845
846 # reloading the same config should leave the builder unchanged
847 master.loadConfig(wpCfg1)
848 b2 = master.botmaster.builders["builder1"]
849 self.failUnlessIdentical(b1, b2)
850
851 # but changing the parameters of the WithProperties should change it
852 master.loadConfig(wpCfg2)
853 b3 = master.botmaster.builders["builder1"]
854 self.failIf(b1 is b3)
855
856 # again, reloading same config should leave the builder unchanged
857 master.loadConfig(wpCfg2)
858 b4 = master.botmaster.builders["builder1"]
859 self.failUnlessIdentical(b3, b4)
860
861 def checkIRC(self, m, expected):
862 ircs = {}
863 for irc in self.servers(m, words.IRC):
864 ircs[irc.host] = (irc.nick, irc.channels)
865 self.failUnlessEqual(ircs, expected)
866
867 def testIRC(self):
868 if not words:
869 raise unittest.SkipTest("Twisted Words package is not installed")
870 master = self.buildmaster
871 master.loadChanges()
872 d = master.loadConfig(emptyCfg)
873 e1 = {}
874 d.addCallback(lambda res: self.checkIRC(master, e1))
875 d.addCallback(lambda res: master.loadConfig(ircCfg1))
876 e2 = {'irc.us.freenode.net': ('buildbot', ['twisted'])}
877 d.addCallback(lambda res: self.checkIRC(master, e2))
878 d.addCallback(lambda res: master.loadConfig(ircCfg2))
879 e3 = {'irc.us.freenode.net': ('buildbot', ['twisted']),
880 'irc.example.com': ('otherbot', ['chan1', 'chan2'])}
881 d.addCallback(lambda res: self.checkIRC(master, e3))
882 d.addCallback(lambda res: master.loadConfig(ircCfg3))
883 e4 = {'irc.us.freenode.net': ('buildbot', ['knotted'])}
884 d.addCallback(lambda res: self.checkIRC(master, e4))
885 d.addCallback(lambda res: master.loadConfig(ircCfg1))
886 e5 = {'irc.us.freenode.net': ('buildbot', ['twisted'])}
887 d.addCallback(lambda res: self.checkIRC(master, e5))
888 return d
889
890 def testWebPortnum(self):
891 master = self.buildmaster
892 master.loadChanges()
893
894 d = master.loadConfig(webCfg1)
895 def _check1(res):
896 ports = self.checkPorts(self.buildmaster,
897 [(9999, pb.PBServerFactory), (9980, Site)])
898 p = ports[1]
899 self.p = p
900 # nothing should be changed
901 d.addCallback(_check1)
902
903 d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg1))
904 def _check2(res):
905 ports = self.checkPorts(self.buildmaster,
906 [(9999, pb.PBServerFactory), (9980, Site)])
907 self.failUnlessIdentical(self.p, ports[1],
908 "web port was changed even though "
909 "configuration was not")
910 # WebStatus is no longer a ComparableMixin, so it will be
911 # rebuilt on each reconfig
912 #d.addCallback(_check2)
913
914 d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg2))
915 # changes port to 9981
916 def _check3(p):
917 ports = self.checkPorts(self.buildmaster,
918 [(9999, pb.PBServerFactory), (9981, Site)])
919 self.failIf(self.p is ports[1],
920 "configuration was changed but web port was unchanged")
921 d.addCallback(_check3)
922
923 d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg3))
924 # make 9981 on only localhost
925 def _check4(p):
926 ports = self.checkPorts(self.buildmaster,
927 [(9999, pb.PBServerFactory), (9981, Site)])
928 self.failUnlessEqual(ports[1].kwargs['interface'], "127.0.0.1")
929 d.addCallback(_check4)
930
931 d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
932 d.addCallback(lambda res:
933 self.checkPorts(self.buildmaster,
934 [(9999, pb.PBServerFactory)]))
935 return d
936
937 def testWebPathname(self):
938 master = self.buildmaster
939 master.loadChanges()
940
941 d = master.loadConfig(webNameCfg1)
942 def _check1(res):
943 self.checkPorts(self.buildmaster,
944 [(9999, pb.PBServerFactory),
945 ('~/.twistd-web-pb', pb.PBServerFactory)])
946 unixports = self.UNIXports(self.buildmaster)
947 self.f = f = unixports[0].args[1]
948 self.failUnless(isinstance(f.root, ResourcePublisher))
949 d.addCallback(_check1)
950
951 d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg1))
952 # nothing should be changed
953 def _check2(res):
954 self.checkPorts(self.buildmaster,
955 [(9999, pb.PBServerFactory),
956 ('~/.twistd-web-pb', pb.PBServerFactory)])
957 newf = self.UNIXports(self.buildmaster)[0].args[1]
958 self.failUnlessIdentical(self.f, newf,
959 "web factory was changed even though "
960 "configuration was not")
961 # WebStatus is no longer a ComparableMixin, so it will be
962 # rebuilt on each reconfig
963 #d.addCallback(_check2)
964
965 d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg2))
966 def _check3(res):
967 self.checkPorts(self.buildmaster,
968 [(9999, pb.PBServerFactory),
969 ('./bar.socket', pb.PBServerFactory)])
970 newf = self.UNIXports(self.buildmaster)[0].args[1],
971 self.failIf(self.f is newf,
972 "web factory was unchanged but "
973 "configuration was changed")
974 d.addCallback(_check3)
975
976 d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
977 d.addCallback(lambda res:
978 self.checkPorts(self.buildmaster,
979 [(9999, pb.PBServerFactory)]))
980 return d
981
982 def testDebugPassword(self):
983 master = self.buildmaster
984
985 master.loadConfig(debugPasswordCfg)
986 self.failUnlessEqual(master.checker.users,
987 {"change": "changepw",
988 "debug": "sekrit"})
989
990 master.loadConfig(debugPasswordCfg)
991 self.failUnlessEqual(master.checker.users,
992 {"change": "changepw",
993 "debug": "sekrit"})
994
995 master.loadConfig(emptyCfg)
996 self.failUnlessEqual(master.checker.users,
997 {"change": "changepw"})
998
999 def testLocks(self):
1000 master = self.buildmaster
1001 botmaster = master.botmaster
1002
1003 # make sure that c['interlocks'] is rejected properly
1004 self.failUnlessRaises(KeyError, master.loadConfig, interlockCfgBad)
1005 # and that duplicate-named Locks are caught
1006 self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad1)
1007 self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad2)
1008 self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad3)
1009
1010 # create a Builder that uses Locks
1011 master.loadConfig(lockCfg1a)
1012 b1 = master.botmaster.builders["builder1"]
1013 self.failUnlessEqual(len(b1.locks), 2)
1014
1015 # reloading the same config should not change the Builder
1016 master.loadConfig(lockCfg1a)
1017 self.failUnlessIdentical(b1, master.botmaster.builders["builder1"])
1018 # but changing the set of locks used should change it
1019 master.loadConfig(lockCfg1b)
1020 self.failIfIdentical(b1, master.botmaster.builders["builder1"])
1021 b1 = master.botmaster.builders["builder1"]
1022 self.failUnlessEqual(len(b1.locks), 1)
1023
1024 # similar test with step-scoped locks
1025 master.loadConfig(lockCfg2a)
1026 b1 = master.botmaster.builders["builder1"]
1027 # reloading the same config should not change the Builder
1028 master.loadConfig(lockCfg2a)
1029 self.failUnlessIdentical(b1, master.botmaster.builders["builder1"])
1030 # but changing the set of locks used should change it
1031 master.loadConfig(lockCfg2b)
1032 self.failIfIdentical(b1, master.botmaster.builders["builder1"])
1033 b1 = master.botmaster.builders["builder1"]
1034 # remove the locks entirely
1035 master.loadConfig(lockCfg2c)
1036 self.failIfIdentical(b1, master.botmaster.builders["builder1"])
1037
1038 def testNoChangeHorizon(self):
1039 master = self.buildmaster
1040 master.loadChanges()
1041 sourcesCfg = emptyCfg + \
1042 """
1043 from buildbot.changes.pb import PBChangeSource
1044 c['change_source'] = PBChangeSource()
1045 """
1046 d = master.loadConfig(sourcesCfg)
1047 def _check1(res):
1048 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
1049 self.failUnlessEqual(self.buildmaster.change_svc.changeHorizon, 0)
1050 d.addCallback(_check1)
1051 return d
1052
1053 def testChangeHorizon(self):
1054 master = self.buildmaster
1055 master.loadChanges()
1056 sourcesCfg = emptyCfg + \
1057 """
1058 from buildbot.changes.pb import PBChangeSource
1059 c['change_source'] = PBChangeSource()
1060 c['changeHorizon'] = 5
1061 """
1062 d = master.loadConfig(sourcesCfg)
1063 def _check1(res):
1064 self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
1065 self.failUnlessEqual(self.buildmaster.change_svc.changeHorizon, 5)
1066 d.addCallback(_check1)
1067 return d
1068
1069 class ConfigElements(unittest.TestCase):
1070 # verify that ComparableMixin is working
1071 def testSchedulers(self):
1072 s1 = scheduler.Scheduler(name='quick', branch=None,
1073 treeStableTimer=30,
1074 builderNames=['quick'])
1075 s2 = scheduler.Scheduler(name="all", branch=None,
1076 treeStableTimer=5*60,
1077 builderNames=["a", "b"])
1078 s3 = scheduler.Try_Userpass("try", ["a","b"], port=9989,
1079 userpass=[("foo","bar")])
1080 s1a = scheduler.Scheduler(name='quick', branch=None,
1081 treeStableTimer=30,
1082 builderNames=['quick'])
1083 s2a = scheduler.Scheduler(name="all", branch=None,
1084 treeStableTimer=5*60,
1085 builderNames=["a", "b"])
1086 s3a = scheduler.Try_Userpass("try", ["a","b"], port=9989,
1087 userpass=[("foo","bar")])
1088 self.failUnless(s1 == s1)
1089 self.failUnless(s1 == s1a)
1090 self.failUnless(s1a in [s1, s2, s3])
1091 self.failUnless(s2a in [s1, s2, s3])
1092 self.failUnless(s3a in [s1, s2, s3])
1093
1094
1095
1096 class ConfigFileTest(unittest.TestCase):
1097
1098 def testFindConfigFile(self):
1099 os.mkdir("test_cf")
1100 open(os.path.join("test_cf", "master.cfg"), "w").write(emptyCfg)
1101 slaveportCfg = emptyCfg + "c['slavePortnum'] = 9000\n"
1102 open(os.path.join("test_cf", "alternate.cfg"), "w").write(slaveportCfg)
1103
1104 m = BuildMaster("test_cf")
1105 m.loadTheConfigFile()
1106 self.failUnlessEqual(m.slavePortnum, "tcp:9999")
1107
1108 m = BuildMaster("test_cf", "alternate.cfg")
1109 m.loadTheConfigFile()
1110 self.failUnlessEqual(m.slavePortnum, "tcp:9000")
1111
1112
1113 class MyTarget(base.StatusReceiverMultiService):
1114 def __init__(self, name):
1115 self.name = name
1116 base.StatusReceiverMultiService.__init__(self)
1117 def startService(self):
1118 # make a note in a list stashed in the BuildMaster
1119 self.parent.targetevents.append(("start", self.name))
1120 return base.StatusReceiverMultiService.startService(self)
1121 def stopService(self):
1122 self.parent.targetevents.append(("stop", self.name))
1123 return base.StatusReceiverMultiService.stopService(self)
1124
1125 class MySlowTarget(MyTarget):
1126 def stopService(self):
1127 from twisted.internet import reactor
1128 d = base.StatusReceiverMultiService.stopService(self)
1129 def stall(res):
1130 d2 = defer.Deferred()
1131 reactor.callLater(0.1, d2.callback, res)
1132 return d2
1133 d.addCallback(stall)
1134 m = self.parent
1135 def finishedStalling(res):
1136 m.targetevents.append(("stop", self.name))
1137 return res
1138 d.addCallback(finishedStalling)
1139 return d
1140
1141 # we can't actually startService a buildmaster with a config that uses a
1142 # fixed slavePortnum like 9999, so instead this makes it possible to pass '0'
1143 # for the first time, and then substitute back in the allocated port number
1144 # on subsequent passes.
1145 startableEmptyCfg = emptyCfg + \
1146 """
1147 c['slavePortnum'] = %d
1148 """
1149
1150 targetCfg1 = startableEmptyCfg + \
1151 """
1152 from buildbot.test.test_config import MyTarget
1153 c['status'] = [MyTarget('a')]
1154 """
1155
1156 targetCfg2 = startableEmptyCfg + \
1157 """
1158 from buildbot.test.test_config import MySlowTarget
1159 c['status'] = [MySlowTarget('b')]
1160 """
1161
1162 class StartService(unittest.TestCase):
1163 def tearDown(self):
1164 return self.master.stopService()
1165
1166 def testStartService(self):
1167 os.mkdir("test_ss")
1168 self.master = m = BuildMaster("test_ss")
1169 # inhibit the usual read-config-on-startup behavior
1170 m.readConfig = True
1171 m.startService()
1172 d = m.loadConfig(startableEmptyCfg % 0)
1173 d.addCallback(self._testStartService_0)
1174 return d
1175
1176 def _testStartService_0(self, res):
1177 m = self.master
1178 m.targetevents = []
1179 # figure out what port got allocated
1180 self.portnum = m.slavePort._port.getHost().port
1181 d = m.loadConfig(targetCfg1 % self.portnum)
1182 d.addCallback(self._testStartService_1)
1183 return d
1184
1185 def _testStartService_1(self, res):
1186 self.failUnlessEqual(len(self.master.statusTargets), 1)
1187 self.failUnless(isinstance(self.master.statusTargets[0], MyTarget))
1188 self.failUnlessEqual(self.master.targetevents,
1189 [('start', 'a')])
1190 self.master.targetevents = []
1191 # reloading the same config should not start or stop the target
1192 d = self.master.loadConfig(targetCfg1 % self.portnum)
1193 d.addCallback(self._testStartService_2)
1194 return d
1195
1196 def _testStartService_2(self, res):
1197 self.failUnlessEqual(self.master.targetevents, [])
1198 # but loading a new config file should stop the old one, then
1199 # start the new one
1200 d = self.master.loadConfig(targetCfg2 % self.portnum)
1201 d.addCallback(self._testStartService_3)
1202 return d
1203
1204 def _testStartService_3(self, res):
1205 self.failUnlessEqual(self.master.targetevents,
1206 [('stop', 'a'), ('start', 'b')])
1207 self.master.targetevents = []
1208 # and going back to the old one should do the same, in the same
1209 # order, even though the current MySlowTarget takes a moment to shut
1210 # down
1211 d = self.master.loadConfig(targetCfg1 % self.portnum)
1212 d.addCallback(self._testStartService_4)
1213 return d
1214
1215 def _testStartService_4(self, res):
1216 self.failUnlessEqual(self.master.targetevents,
1217 [('stop', 'b'), ('start', 'a')])
1218
1219 cfg1 = \
1220 """
1221 from buildbot.process.factory import BuildFactory, s
1222 from buildbot.steps.shell import ShellCommand
1223 from buildbot.steps.source import Darcs
1224 from buildbot.buildslave import BuildSlave
1225 from buildbot.config import BuilderConfig
1226 BuildmasterConfig = c = {}
1227 c['slaves'] = [BuildSlave('bot1', 'pw1')]
1228 c['schedulers'] = []
1229 c['slavePortnum'] = 9999
1230 f1 = BuildFactory([ShellCommand(command='echo yes'),
1231 s(ShellCommand, command='old-style'),
1232 ])
1233 f1.addStep(Darcs(repourl='http://buildbot.net/repos/trunk'))
1234 f1.addStep(ShellCommand, command='echo old-style')
1235 c['builders'] = [
1236 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
1237 ]
1238 """
1239
1240 cfg1_bad = \
1241 """
1242 from buildbot.process.factory import BuildFactory, s
1243 from buildbot.steps.shell import ShellCommand
1244 from buildbot.steps.source import Darcs
1245 from buildbot.buildslave import BuildSlave
1246 from buildbot.config import BuilderConfig
1247 BuildmasterConfig = c = {}
1248 c['slaves'] = [BuildSlave('bot1', 'pw1')]
1249 c['schedulers'] = []
1250 c['slavePortnum'] = 9999
1251 f1 = BuildFactory([ShellCommand(command='echo yes'),
1252 s(ShellCommand, command='old-style'),
1253 ])
1254 # it should be this:
1255 #f1.addStep(ShellCommand(command='echo args'))
1256 # but an easy mistake is to do this:
1257 f1.addStep(ShellCommand(), command='echo args')
1258 # this test makes sure this error doesn't get ignored
1259 c['builders'] = [
1260 BuilderConfig(name='builder1', slavename='bot1', factory=f1),
1261 ]
1262 """
1263
1264 class Factories(unittest.TestCase):
1265 def printExpecting(self, factory, args):
1266 factory_keys = factory[1].keys()
1267 factory_keys.sort()
1268 args_keys = args.keys()
1269 args_keys.sort()
1270
1271 print
1272 print "factory had:"
1273 for k in factory_keys:
1274 print k
1275 print "but we were expecting:"
1276 for k in args_keys:
1277 print k
1278
1279 def failUnlessExpectedShell(self, factory, defaults=True, **kwargs):
1280 shell_args = {}
1281 if defaults:
1282 shell_args.update({'descriptionDone': None,
1283 'description': None,
1284 'workdir': None,
1285 'logfiles': {},
1286 'lazylogfiles': False,
1287 'usePTY': "slave-config",
1288 })
1289 shell_args.update(kwargs)
1290 self.failUnlessIdentical(factory[0], ShellCommand)
1291 if factory[1] != shell_args:
1292 self.printExpecting(factory, shell_args)
1293 self.failUnlessEqual(factory[1], shell_args)
1294
1295 def failUnlessExpectedDarcs(self, factory, **kwargs):
1296 darcs_args = {'workdir': None,
1297 'alwaysUseLatest': False,
1298 'mode': 'update',
1299 'timeout': 1200,
1300 'retry': None,
1301 'baseURL': None,
1302 'defaultBranch': None,
1303 'logfiles': {},
1304 'lazylogfiles' : False,
1305 }
1306 darcs_args.update(kwargs)
1307 self.failUnlessIdentical(factory[0], Darcs)
1308 if factory[1] != darcs_args:
1309 self.printExpecting(factory, darcs_args)
1310 self.failUnlessEqual(factory[1], darcs_args)
1311
1312 def testSteps(self):
1313 m = BuildMaster(".")
1314 m.loadConfig(cfg1)
1315 b = m.botmaster.builders["builder1"]
1316 steps = b.buildFactory.steps
1317 self.failUnlessEqual(len(steps), 4)
1318
1319 self.failUnlessExpectedShell(steps[0], command="echo yes")
1320 self.failUnlessExpectedShell(steps[1], defaults=False,
1321 command="old-style")
1322 self.failUnlessExpectedDarcs(steps[2],
1323 repourl="http://buildbot.net/repos/trunk")
1324 self.failUnlessExpectedShell(steps[3], defaults=False,
1325 command="echo old-style")
1326
1327 def testBadAddStepArguments(self):
1328 m = BuildMaster(".")
1329 self.failUnlessRaises(ArgumentsInTheWrongPlace, m.loadConfig, cfg1_bad)
1330
1331 def _loop(self, orig):
1332 step_class, kwargs = orig.getStepFactory()
1333 newstep = step_class(**kwargs)
1334 return newstep
1335
1336 def testAllSteps(self):
1337 # make sure that steps can be created from the factories that they
1338 # return
1339 for s in ( dummy.Dummy(), dummy.FailingDummy(), dummy.RemoteDummy(),
1340 maxq.MaxQ("testdir"),
1341 python.BuildEPYDoc(), python.PyFlakes(),
1342 python_twisted.HLint(),
1343 python_twisted.Trial(testpath=None, tests="tests"),
1344 python_twisted.ProcessDocs(), python_twisted.BuildDebs(),
1345 python_twisted.RemovePYCs(),
1346 shell.ShellCommand(), shell.TreeSize(),
1347 shell.Configure(), shell.Compile(), shell.Test(),
1348 source.CVS("cvsroot", "module"),
1349 source.SVN("svnurl"), source.Darcs("repourl"),
1350 source.Git("repourl"),
1351 source.Arch("url", "version"),
1352 source.Bazaar("url", "version", "archive"),
1353 source.Bzr("repourl"),
1354 source.Mercurial("repourl"),
1355 source.P4("p4base"),
1356 source.P4Sync(1234, "p4user", "passwd", "client",
1357 mode="copy"),
1358 source.Monotone("server", "branch"),
1359 transfer.FileUpload("src", "dest"),
1360 transfer.FileDownload("src", "dest"),
1361 ):
1362 try:
1363 self._loop(s)
1364 except:
1365 print "error checking %s" % s
1366 raise
1367
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/test/test_changes.py ('k') | third_party/buildbot_7_12/buildbot/test/test_console.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698