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

Side by Side Diff: third_party/buildbot_7_12/buildbot/test/test_status.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_status -*-
2
3 import email, os
4 import operator
5
6 from zope.interface import implements
7 from twisted.internet import defer, reactor
8 from twisted.trial import unittest
9
10 from buildbot import interfaces
11 from buildbot.sourcestamp import SourceStamp
12 from buildbot.process.base import BuildRequest, Build
13 from buildbot.status import builder, base, words, progress
14 from buildbot.changes.changes import Change
15 from buildbot.process.builder import Builder
16 from time import sleep
17
18 import sys
19 if sys.version_info[:3] < (2,4,0):
20 from sets import Set as set
21
22 mail = None
23 try:
24 from buildbot.status import mail
25 except ImportError:
26 pass
27 from buildbot.status import progress, client # NEEDS COVERAGE
28 from buildbot.test.runutils import RunMixin, setupBuildStepStatus, rmtree
29
30 class MyStep:
31 build = None
32 def getName(self):
33 return "step"
34 def getResults(self):
35 return (builder.SUCCESS, "yay")
36
37 class MyLogFileProducer(builder.LogFileProducer):
38 # The reactor.callLater(0) in LogFileProducer.resumeProducing is a bit of
39 # a nuisance from a testing point of view. This subclass adds a Deferred
40 # to that call so we can find out when it is complete.
41 def resumeProducing(self):
42 d = defer.Deferred()
43 reactor.callLater(0, self._resumeProducing, d)
44 return d
45 def _resumeProducing(self, d):
46 builder.LogFileProducer._resumeProducing(self)
47 reactor.callLater(0, d.callback, None)
48
49 class MyLog(builder.LogFile):
50 def __init__(self, basedir, name, text=None, step=None):
51 self.fakeBuilderBasedir = basedir
52 if not step:
53 step = MyStep()
54 builder.LogFile.__init__(self, step, name, name)
55 if text:
56 self.addStdout(text)
57 self.finish()
58 def getFilename(self):
59 return os.path.join(self.fakeBuilderBasedir, self.name)
60
61 def subscribeConsumer(self, consumer):
62 p = MyLogFileProducer(self, consumer)
63 d = p.resumeProducing()
64 return d
65
66 class MyHTMLLog(builder.HTMLLogFile):
67 def __init__(self, basedir, name, html):
68 step = MyStep()
69 builder.HTMLLogFile.__init__(self, step, name, name, html)
70
71 class MyLogSubscriber:
72 def __init__(self):
73 self.chunks = []
74 def logChunk(self, build, step, log, channel, text):
75 self.chunks.append((channel, text))
76
77 class MyLogConsumer:
78 def __init__(self, limit=None):
79 self.chunks = []
80 self.finished = False
81 self.limit = limit
82 def registerProducer(self, producer, streaming):
83 self.producer = producer
84 self.streaming = streaming
85 def unregisterProducer(self):
86 self.producer = None
87 def writeChunk(self, chunk):
88 self.chunks.append(chunk)
89 if self.limit:
90 self.limit -= 1
91 if self.limit == 0:
92 self.producer.pauseProducing()
93 def finish(self):
94 self.finished = True
95
96 if mail:
97 class MyMailer(mail.MailNotifier):
98 def sendMessage(self, m, recipients):
99 self.parent.messages.append((m, recipients))
100
101 class MyStatus:
102 def getBuildbotURL(self):
103 return self.url
104 def getURLForThing(self, thing):
105 return None
106 def getProjectName(self):
107 return "myproj"
108
109 class MyBuilder(builder.BuilderStatus):
110 nextBuildNumber = 0
111 def newBuild(self):
112 number = self.nextBuildNumber
113 self.nextBuildNumber += 1
114 s = MyBuild(self, number, None, False)
115 s.waitUntilFinished().addCallback(self._buildFinished)
116 return s
117
118 class MyBuild(builder.BuildStatus):
119 testlogs = []
120 def __init__(self, parent, number, results, finished=True):
121 builder.BuildStatus.__init__(self, parent, number)
122 self.results = results
123 self.source = SourceStamp(revision="1.14")
124 self.reason = "build triggered by changes"
125 self.finished = finished
126 def getLogs(self):
127 return self.testlogs
128 def buildStarted(self, build, started):
129 self.started = started
130 self.builder.buildStarted(self)
131
132 class MyLookup:
133 implements(interfaces.IEmailLookup)
134
135 def getAddress(self, user):
136 d = defer.Deferred()
137 # With me now is Mr Thomas Walters of West Hartlepool who is totally
138 # invisible.
139 if user == "Thomas_Walters":
140 d.callback(None)
141 else:
142 d.callback(user + "@" + "dev.com")
143 return d
144
145 def customTextMailMessage(attrs):
146 logLines = 3
147 text = list()
148 text.append("STATUS: %s" % attrs['result'].title())
149 text.append("")
150 text.extend([c.asText() for c in attrs['changes']])
151 text.append("")
152 name, url, lines, status = attrs['logs'][-1]
153 text.append("Last %d lines of '%s':" % (logLines, name))
154 text.extend(["\t%s\n" % line for line in lines[len(lines)-logLines:]])
155 text.append("")
156 text.append("Build number was: %s" % attrs['buildProperties']['buildnumber'] )
157 text.append("")
158 text.append("-buildbot")
159 return ("\n".join(text), 'plain')
160
161 def customHTMLMailMessage(attrs):
162 logLines = 3
163 text = list()
164 text.append("<h3>STATUS <a href='%s'>%s</a>:</h3>" % (attrs['buildURL'],
165 attrs['result'].title( )))
166 text.append("<h4>Recent Changes:</h4>")
167 text.extend([c.asHTML() for c in attrs['changes']])
168 name, url, lines, status = attrs['logs'][-1]
169 text.append("<h4>Last %d lines of '%s':</h4>" % (logLines, name))
170 text.append("<p>")
171 text.append("<br>".join([line for line in lines[len(lines)-logLines:]]))
172 text.append("</p>")
173 text.append("<p>Build number was: %s</p>" % attrs['buildProperties']['buildn umber'])
174 text.append("<br>")
175 text.append("<b>-<a href='%s'>buildbot</a></b>" % attrs['buildbotURL'])
176 return ("\n".join(text), 'html')
177
178 class Mail(unittest.TestCase):
179
180 def setUp(self):
181 self.builder = MyBuilder("builder1")
182
183 def stall(self, res, timeout):
184 d = defer.Deferred()
185 reactor.callLater(timeout, d.callback, res)
186 return d
187
188 def makeBuild(self, number, results):
189 return MyBuild(self.builder, number, results)
190
191 def failUnlessIn(self, substring, string):
192 self.failUnless(string.find(substring) != -1,
193 "didn't see '%s' in '%s'" % (substring, string))
194
195 def getProjectName(self):
196 return "PROJECT"
197
198 def getBuildbotURL(self):
199 return "BUILDBOT_URL"
200
201 def getURLForThing(self, thing):
202 return None
203
204 def testBuild1(self):
205 mailer = MyMailer(fromaddr="buildbot@example.com",
206 extraRecipients=["recip@example.com",
207 "recip2@example.com"],
208 lookup=mail.Domain("dev.com"))
209 mailer.parent = self
210 mailer.master_status = self
211 self.messages = []
212
213 b1 = self.makeBuild(3, builder.SUCCESS)
214 b1.blamelist = ["bob"]
215
216 mailer.buildFinished("builder1", b1, b1.results)
217 self.failUnless(len(self.messages) == 1)
218 m,r = self.messages.pop()
219 t = m.as_string()
220 self.failUnlessIn("To: bob@dev.com\n", t)
221 self.failUnlessIn("CC: recip2@example.com, recip@example.com\n", t)
222 self.failUnlessIn("From: buildbot@example.com\n", t)
223 self.failUnlessIn("Subject: buildbot success in PROJECT on builder1\n", t)
224 self.failUnlessIn("Date: ", t)
225 self.failUnlessIn("Build succeeded!\n", t)
226 self.failUnlessIn("Buildbot URL: BUILDBOT_URL\n", t)
227
228 def testBuild2(self):
229 mailer = MyMailer(fromaddr="buildbot@example.com",
230 extraRecipients=["recip@example.com",
231 "recip2@example.com"],
232 lookup="dev.com",
233 sendToInterestedUsers=False)
234 mailer.parent = self
235 mailer.master_status = self
236 self.messages = []
237
238 b1 = self.makeBuild(3, builder.SUCCESS)
239 b1.blamelist = ["bob"]
240
241 mailer.buildFinished("builder1", b1, b1.results)
242 self.failUnless(len(self.messages) == 1)
243 m,r = self.messages.pop()
244 t = m.as_string()
245 self.failUnlessIn("To: recip2@example.com, "
246 "recip@example.com\n", t)
247 self.failUnlessIn("From: buildbot@example.com\n", t)
248 self.failUnlessIn("Subject: buildbot success in PROJECT on builder1\n", t)
249 self.failUnlessIn("Build succeeded!\n", t)
250 self.failUnlessIn("Buildbot URL: BUILDBOT_URL\n", t)
251
252 def testBuildStatusCategory(self):
253 # a status client only interested in a category should only receive
254 # from that category
255 mailer = MyMailer(fromaddr="buildbot@example.com",
256 extraRecipients=["recip@example.com",
257 "recip2@example.com"],
258 lookup="dev.com",
259 sendToInterestedUsers=False,
260 categories=["debug"])
261
262 mailer.parent = self
263 mailer.master_status = self
264 self.messages = []
265
266 b1 = self.makeBuild(3, builder.SUCCESS)
267 b1.blamelist = ["bob"]
268
269 mailer.buildFinished("builder1", b1, b1.results)
270 self.failIf(self.messages)
271
272 def testBuilderCategory(self):
273 # a builder in a certain category should notify status clients that
274 # did not list categories, or categories including this one
275 mailer1 = MyMailer(fromaddr="buildbot@example.com",
276 extraRecipients=["recip@example.com",
277 "recip2@example.com"],
278 lookup="dev.com",
279 sendToInterestedUsers=False)
280 mailer2 = MyMailer(fromaddr="buildbot@example.com",
281 extraRecipients=["recip@example.com",
282 "recip2@example.com"],
283 lookup="dev.com",
284 sendToInterestedUsers=False,
285 categories=["active"])
286 mailer3 = MyMailer(fromaddr="buildbot@example.com",
287 extraRecipients=["recip@example.com",
288 "recip2@example.com"],
289 lookup="dev.com",
290 sendToInterestedUsers=False,
291 categories=["active", "debug"])
292
293 builderd = MyBuilder("builder2", "debug")
294
295 mailer1.parent = self
296 mailer1.master_status = self
297 mailer2.parent = self
298 mailer2.master_status = self
299 mailer3.parent = self
300 mailer3.master_status = self
301 self.messages = []
302
303 t = mailer1.builderAdded("builder2", builderd)
304 self.assertEqual(len(mailer1.watched), 1)
305 self.assertEqual(t, mailer1)
306 t = mailer2.builderAdded("builder2", builderd)
307 self.assertEqual(len(mailer2.watched), 0)
308 self.assertEqual(t, None)
309 t = mailer3.builderAdded("builder2", builderd)
310 self.assertEqual(len(mailer3.watched), 1)
311 self.assertEqual(t, mailer3)
312
313 b2 = MyBuild(builderd, 3, builder.SUCCESS)
314 b2.blamelist = ["bob"]
315
316 mailer1.buildFinished("builder2", b2, b2.results)
317 self.failUnlessEqual(len(self.messages), 1)
318 self.messages = []
319 mailer2.buildFinished("builder2", b2, b2.results)
320 self.failUnlessEqual(len(self.messages), 0)
321 self.messages = []
322 mailer3.buildFinished("builder2", b2, b2.results)
323 self.failUnlessEqual(len(self.messages), 1)
324
325 def testCustomTextMessage(self):
326 basedir = "test_custom_text_mesg"
327 os.mkdir(basedir)
328 mailer = MyMailer(fromaddr="buildbot@example.com", mode="problem",
329 extraRecipients=["recip@example.com",
330 "recip2@example.com"],
331 lookup=MyLookup(),
332 customMesg=customTextMailMessage)
333 mailer.parent = self
334 mailer.master_status = self
335 self.messages = []
336
337 b1 = self.makeBuild(4, builder.FAILURE)
338 b1.setProperty('buildnumber', 1, 'Build')
339 b1.setText(["snarkleack", "polarization", "failed"])
340 b1.blamelist = ["dev3", "dev3", "dev3", "dev4",
341 "Thomas_Walters"]
342 b1.source.changes = (Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 123),
343 Change(who = 'author2', files = ['file2'], comments = 'comment2', revision = 456))
344 b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"),
345 MyLog(basedir, 'test', "Test log here\nTest 1 failed\nTes t 2 failed\nTest 3 failed\nTest 4 failed\n")]
346
347 mailer.buildFinished("builder1", b1, b1.results)
348 m,r = self.messages.pop()
349 t = m.as_string()
350 #
351 # Uncomment to review custom message
352 #
353 #self.fail(t)
354 self.failUnlessIn("comment1", t)
355 self.failUnlessIn("comment2", t)
356 self.failUnlessIn("Test 4 failed", t)
357 self.failUnlessIn("number was: 1", t)
358
359
360 def testCustomHTMLMessage(self):
361 basedir = "test_custom_HTML_mesg"
362 os.mkdir(basedir)
363 mailer = MyMailer(fromaddr="buildbot@example.com", mode="problem",
364 extraRecipients=["recip@example.com",
365 "recip2@example.com"],
366 lookup=MyLookup(),
367 customMesg=customHTMLMailMessage)
368 mailer.parent = self
369 mailer.master_status = self
370 self.messages = []
371
372 b1 = self.makeBuild(4, builder.FAILURE)
373 b1.setProperty('buildnumber', 1, 'Build')
374 b1.setText(["snarkleack", "polarization", "failed"])
375 b1.blamelist = ["dev3", "dev3", "dev3", "dev4",
376 "Thomas_Walters"]
377 b1.source.changes = (Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 123),
378 Change(who = 'author2', files = ['file2'], comments = 'comment2', revision = 456))
379 b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"),
380 MyLog(basedir, 'test', "Test log here\nTest 1 failed\nTes t 2 failed\nTest 3 failed\nTest 4 failed\n")]
381
382 mailer.buildFinished("builder1", b1, b1.results)
383 m,r = self.messages.pop()
384 t = m.as_string()
385 #
386 # Uncomment to review custom message
387 #
388 #self.fail(t)
389 self.failUnlessIn("<h4>Last 3 lines of 'step.test':</h4>", t)
390 self.failUnlessIn("<p>Changed by: <b>author2</b><br />", t)
391 self.failUnlessIn("Test 3 failed", t)
392 self.failUnlessIn("number was: 1", t)
393
394 def testShouldAttachLog(self):
395 mailer = mail.MailNotifier(fromaddr="buildbot@example.com", addLogs=True )
396 self.assertTrue(mailer._shouldAttachLog('anything'))
397 mailer = mail.MailNotifier(fromaddr="buildbot@example.com", addLogs=Fals e)
398 self.assertFalse(mailer._shouldAttachLog('anything'))
399 mailer = mail.MailNotifier(fromaddr="buildbot@example.com", addLogs=['so mething'])
400 self.assertFalse(mailer._shouldAttachLog('anything'))
401 self.assertTrue(mailer._shouldAttachLog('something'))
402
403 def testShouldAttachPatches(self):
404 basedir = "test_should_attach_patches"
405 os.mkdir(basedir)
406 b1 = self.makeBuild(4, builder.FAILURE)
407 b1.setProperty('buildnumber', 1, 'Build')
408 b1.setText(["snarkleack", "polarization", "failed"])
409 b1.blamelist = ["dev3", "dev3", "dev3", "dev4",
410 "Thomas_Walters"]
411 b1.source.changes = (Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 123),
412 Change(who = 'author2', files = ['file2'], comments = 'comment2', revision = 456))
413 b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"),
414 MyLog(basedir, 'test', "Test log here\nTest 1 failed\nTes t 2 failed\nTest 3 failed\nTest 4 failed\n")]
415 b1.source.patch = (0, '--- /dev/null\n+++ a_file\n', None)
416
417 mailer = MyMailer(fromaddr="buildbot@example.com", addPatch=True)
418 mailer.parent = self
419 mailer.master_status = self
420 self.messages = []
421 mailer.buildFinished("builder1", b1, b1.results)
422 m,r = self.messages.pop()
423 self.assertTrue(m.is_multipart())
424 self.assertEqual(len([True for i in m.walk()]), 3)
425
426 mailer = MyMailer(fromaddr="buildbot@example.com", addPatch=False)
427 mailer.parent = self
428 mailer.master_status = self
429 self.messages = []
430 mailer.buildFinished("builder1", b1, b1.results)
431 m,r = self.messages.pop()
432 self.assertFalse(m.is_multipart())
433 self.assertEqual(len([True for i in m.walk()]), 1)
434
435 mailer = MyMailer(fromaddr="buildbot@example.com")
436 mailer.parent = self
437 mailer.master_status = self
438 self.messages = []
439 mailer.buildFinished("builder1", b1, b1.results)
440 m,r = self.messages.pop()
441 self.assertTrue(m.is_multipart())
442 self.assertEqual(len([True for i in m.walk()]), 3)
443
444
445 def testFailure(self):
446 mailer = MyMailer(fromaddr="buildbot@example.com", mode="problem",
447 extraRecipients=["recip@example.com",
448 "recip2@example.com"],
449 lookup=MyLookup())
450 mailer.parent = self
451 mailer.master_status = self
452 self.messages = []
453
454 b1 = self.makeBuild(3, builder.SUCCESS)
455 b1.blamelist = ["dev1", "dev2"]
456 b2 = self.makeBuild(4, builder.FAILURE)
457 b2.setText(["snarkleack", "polarization", "failed"])
458 b2.blamelist = ["dev3", "dev3", "dev3", "dev4",
459 "Thomas_Walters"]
460 mailer.buildFinished("builder1", b1, b1.results)
461 self.failIf(self.messages)
462 mailer.buildFinished("builder1", b2, b2.results)
463 self.failUnless(len(self.messages) == 1)
464 m,r = self.messages.pop()
465 t = m.as_string()
466 self.failUnlessIn("To: dev3@dev.com, dev4@dev.com\n", t)
467 self.failUnlessIn("CC: recip2@example.com, recip@example.com\n", t)
468 self.failUnlessIn("From: buildbot@example.com\n", t)
469 self.failUnlessIn("Subject: buildbot failure in PROJECT on builder1\n", t)
470 self.failUnlessIn("The Buildbot has detected a new failure", t)
471 self.failUnlessIn("BUILD FAILED: snarkleack polarization failed\n", t)
472 self.failUnlessEqual(set(r), set(["dev3@dev.com", "dev4@dev.com",
473 "recip2@example.com", "recip@example.com"]))
474
475
476 def testChange(self):
477 raise unittest.SkipTest("TODO: Fix Build/Builder mock objects to support getPrevBuild()")
478
479 mailer = MyMailer(fromaddr="buildbot@example.com", mode="change",
480 extraRecipients=["bah@bah.bah"],
481 lookup=MyLookup())
482 mailer.parent = self
483 mailer.master_status = self
484 self.messages = []
485
486 b1 = self.makeBuild(1, builder.SUCCESS)
487 b2 = self.makeBuild(2, builder.SUCCESS)
488 b3 = self.makeBuild(3, builder.FAILURE)
489 b4 = self.makeBuild(4, builder.FAILURE)
490 b5 = self.makeBuild(5, builder.SUCCESS)
491 b6 = self.makeBuild(6, builder.SUCCESS)
492
493 # no message on first or repetetive success
494 mailer.buildFinished("builder1", b1, b1.results)
495 self.failIf(self.messages)
496 mailer.buildFinished("builder1", b2, b2.results)
497 self.failIf(self.messages)
498
499 # message on first fail only
500 mailer.buildFinished("builder1", b3, b3.results)
501 self.failUnless(len(self.messages) == 1)
502 self.messages.pop()
503 mailer.buildFinished("builder1", b4, b4.results)
504 self.failIf(self.messages)
505
506 # message on first following success
507 mailer.buildFinished("builder1", b5, b5.results)
508 self.failUnless(len(self.messages) == 1)
509 self.messages.pop()
510 mailer.buildFinished("builder1", b6, b6.results)
511 self.failIf(self.messages)
512
513
514 def testLogs(self):
515 basedir = "test_status_logs"
516 os.mkdir(basedir)
517 mailer = MyMailer(fromaddr="buildbot@example.com", addLogs=True,
518 extraRecipients=["recip@example.com",
519 "recip2@example.com"])
520 mailer.parent = self
521 mailer.master_status = self
522 self.messages = []
523
524 b1 = self.makeBuild(3, builder.WARNINGS)
525 b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"),
526 MyLog(basedir,
527 'test', "Test log here\nTest 4 failed\n"),
528 ]
529 b1.text = ["unusual", "gnarzzler", "output"]
530 mailer.buildFinished("builder1", b1, b1.results)
531 self.failUnless(len(self.messages) == 1)
532 m,r = self.messages.pop()
533 t = m.as_string()
534 self.failUnlessIn("Subject: buildbot warnings in PROJECT on builder1\n", t)
535 m2 = email.message_from_string(t)
536 p = m2.get_payload()
537 self.failUnlessEqual(len(p), 3)
538
539 self.failUnlessIn("Build Had Warnings: unusual gnarzzler output\n",
540 p[0].get_payload())
541
542 self.failUnlessEqual(p[1].get_filename(), "step.compile")
543 self.failUnlessEqual(p[1].get_payload(), "Compile log here\n")
544
545 self.failUnlessEqual(p[2].get_filename(), "step.test")
546 self.failUnlessIn("Test log here\n", p[2].get_payload())
547
548 def testMail(self):
549 basedir = "test_status_mail"
550 os.mkdir(basedir)
551 dest = os.environ.get("BUILDBOT_TEST_MAIL")
552 if not dest:
553 raise unittest.SkipTest("define BUILDBOT_TEST_MAIL=dest to run this" )
554 mailer = mail.MailNotifier(fromaddr="buildbot@example.com",
555 addLogs=True,
556 extraRecipients=[dest])
557 s = MyStatus()
558 s.url = "project URL"
559 mailer.master_status = s
560
561 b1 = self.makeBuild(3, builder.SUCCESS)
562 b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"),
563 MyLog(basedir,
564 'test', "Test log here\nTest 4 failed\n"),
565 ]
566
567 d = mailer.buildFinished("builder1", b1, b1.results)
568 # When this fires, the mail has been sent, but the SMTP connection is
569 # still up (because smtp.sendmail relies upon the server to hang up).
570 # Spin for a moment to avoid the "unclean reactor" warning that Trial
571 # gives us if we finish before the socket is disconnected. Really,
572 # sendmail() ought to hang up the connection once it is finished:
573 # otherwise a malicious SMTP server could make us consume lots of
574 # memory.
575 d.addCallback(self.stall, 0.1)
576 return d
577
578 if not mail:
579 Mail.skip = "the Twisted Mail package is not installed"
580
581 class Progress(unittest.TestCase):
582 def testWavg(self):
583 bp = progress.BuildProgress([])
584 e = progress.Expectations(bp)
585 # wavg(old, current)
586 self.failUnlessEqual(e.wavg(None, None), None)
587 self.failUnlessEqual(e.wavg(None, 3), 3)
588 self.failUnlessEqual(e.wavg(3, None), 3)
589 self.failUnlessEqual(e.wavg(3, 4), 3.5)
590 e.decay = 0.1
591 self.failUnlessEqual(e.wavg(3, 4), 3.1)
592
593
594 class Results(unittest.TestCase):
595
596 def testAddResults(self):
597 b = builder.BuildStatus(builder.BuilderStatus("test"), 12)
598 testname = ("buildbot", "test", "test_status", "Results",
599 "testAddResults")
600 r1 = builder.TestResult(name=testname,
601 results=builder.SUCCESS,
602 text=["passed"],
603 logs={'output': ""},
604 )
605 b.addTestResult(r1)
606
607 res = b.getTestResults()
608 self.failUnlessEqual(res.keys(), [testname])
609 t = res[testname]
610 self.failUnless(interfaces.ITestResult.providedBy(t))
611 self.failUnlessEqual(t.getName(), testname)
612 self.failUnlessEqual(t.getResults(), builder.SUCCESS)
613 self.failUnlessEqual(t.getText(), ["passed"])
614 self.failUnlessEqual(t.getLogs(), {'output': ""})
615
616 class Log(unittest.TestCase):
617 basedir = "status_log_add"
618
619 def setUp(self):
620 self.tearDown()
621 os.mkdir(self.basedir)
622
623 def tearDown(self):
624 if os.path.exists(self.basedir):
625 rmtree(self.basedir)
626
627 def testAdd(self):
628 l = MyLog(self.basedir, "compile", step=13)
629 self.failUnlessEqual(l.getName(), "compile")
630 self.failUnlessEqual(l.getStep(), 13)
631 l.addHeader("HEADER\n")
632 l.addStdout("Some text\n")
633 l.addStderr("Some error\n")
634 l.addStdout("Some more text\n")
635 self.failIf(l.isFinished())
636 l.finish()
637 self.failUnless(l.isFinished())
638 self.failUnlessEqual(l.getText(),
639 "Some text\nSome error\nSome more text\n")
640 self.failUnlessEqual(l.getTextWithHeaders(),
641 "HEADER\n" +
642 "Some text\nSome error\nSome more text\n")
643 self.failUnlessEqual(len(list(l.getChunks())), 4)
644
645 self.failUnless(l.hasContents())
646 try:
647 os.unlink(l.getFilename())
648 except OSError:
649 os.unlink(l.getFilename() + ".bz2")
650 self.failIf(l.hasContents())
651
652 def TODO_testDuplicate(self):
653 # create multiple logs for the same step with the same logname, make
654 # sure their on-disk filenames are suitably uniquified. This
655 # functionality actually lives in BuildStepStatus and BuildStatus, so
656 # this test must involve more than just the MyLog class.
657
658 # naieve approach, doesn't work
659 l1 = MyLog(self.basedir, "duplicate")
660 l1.addStdout("Some text\n")
661 l1.finish()
662 l2 = MyLog(self.basedir, "duplicate")
663 l2.addStdout("Some more text\n")
664 l2.finish()
665 self.failIfEqual(l1.getFilename(), l2.getFilename())
666
667 def testMerge1(self):
668 l = MyLog(self.basedir, "merge1")
669 l.addHeader("HEADER\n")
670 l.addStdout("Some text\n")
671 l.addStdout("Some more text\n")
672 l.addStdout("more\n")
673 l.finish()
674 self.failUnlessEqual(l.getText(),
675 "Some text\nSome more text\nmore\n")
676 self.failUnlessEqual(l.getTextWithHeaders(),
677 "HEADER\n" +
678 "Some text\nSome more text\nmore\n")
679 self.failUnlessEqual(len(list(l.getChunks())), 2)
680
681 def testMerge2(self):
682 l = MyLog(self.basedir, "merge2")
683 l.addHeader("HEADER\n")
684 for i in xrange(1000):
685 l.addStdout("aaaa")
686 for i in xrange(30):
687 l.addStderr("bbbb")
688 for i in xrange(10):
689 l.addStdout("cc")
690 target = 1000*"aaaa" + 30 * "bbbb" + 10 * "cc"
691 self.failUnlessEqual(len(l.getText()), len(target))
692 self.failUnlessEqual(l.getText(), target)
693 l.finish()
694 self.failUnlessEqual(len(l.getText()), len(target))
695 self.failUnlessEqual(l.getText(), target)
696 self.failUnlessEqual(len(list(l.getChunks())), 4)
697
698 def testMerge3(self):
699 l = MyLog(self.basedir, "merge3")
700 l.chunkSize = 100
701 l.addHeader("HEADER\n")
702 for i in xrange(8):
703 l.addStdout(10*"a")
704 for i in xrange(8):
705 l.addStdout(10*"a")
706 self.failUnlessEqual(list(l.getChunks()),
707 [(builder.HEADER, "HEADER\n"),
708 (builder.STDOUT, 100*"a"),
709 (builder.STDOUT, 60*"a")])
710 l.finish()
711 self.failUnlessEqual(l.getText(), 160*"a")
712
713 def testReadlines(self):
714 l = MyLog(self.basedir, "chunks1")
715 l.addHeader("HEADER\n") # should be ignored
716 l.addStdout("Some text\n")
717 l.addStdout("Some More Text\nAnd Some More\n")
718 l.addStderr("Some Stderr\n")
719 l.addStdout("Last line\n")
720 l.finish()
721 alllines = list(l.readlines())
722 self.failUnlessEqual(len(alllines), 4)
723 self.failUnlessEqual(alllines[0], "Some text\n")
724 self.failUnlessEqual(alllines[2], "And Some More\n")
725 self.failUnlessEqual(alllines[3], "Last line\n")
726 stderr = list(l.readlines(interfaces.LOG_CHANNEL_STDERR))
727 self.failUnlessEqual(len(stderr), 1)
728 self.failUnlessEqual(stderr[0], "Some Stderr\n")
729 lines = l.readlines()
730 if False: # TODO: l.readlines() is not yet an iterator
731 # verify that it really is an iterator
732 line0 = lines.next()
733 self.failUnlessEqual(line0, "Some text\n")
734 line1 = lines.next()
735 line2 = lines.next()
736 self.failUnlessEqual(line2, "And Some More\n")
737
738
739 def testChunks(self):
740 l = MyLog(self.basedir, "chunks2")
741 c1 = l.getChunks()
742 l.addHeader("HEADER\n")
743 l.addStdout("Some text\n")
744 self.failUnlessEqual("".join(l.getChunks(onlyText=True)),
745 "HEADER\nSome text\n")
746 c2 = l.getChunks()
747
748 l.addStdout("Some more text\n")
749 self.failUnlessEqual("".join(l.getChunks(onlyText=True)),
750 "HEADER\nSome text\nSome more text\n")
751 c3 = l.getChunks()
752
753 l.addStdout("more\n")
754 l.finish()
755
756 self.failUnlessEqual(list(c1), [])
757 self.failUnlessEqual(list(c2), [(builder.HEADER, "HEADER\n"),
758 (builder.STDOUT, "Some text\n")])
759 self.failUnlessEqual(list(c3), [(builder.HEADER, "HEADER\n"),
760 (builder.STDOUT,
761 "Some text\nSome more text\n")])
762
763 self.failUnlessEqual(l.getText(),
764 "Some text\nSome more text\nmore\n")
765 self.failUnlessEqual(l.getTextWithHeaders(),
766 "HEADER\n" +
767 "Some text\nSome more text\nmore\n")
768 self.failUnlessEqual(len(list(l.getChunks())), 2)
769
770 def testUpgrade(self):
771 l = MyLog(self.basedir, "upgrade")
772 l.addHeader("HEADER\n")
773 l.addStdout("Some text\n")
774 l.addStdout("Some more text\n")
775 l.addStdout("more\n")
776 l.finish()
777 self.failUnless(l.hasContents())
778 # now doctor it to look like a 0.6.4-era non-upgraded logfile
779 l.entries = list(l.getChunks())
780 del l.filename
781 try:
782 os.unlink(l.getFilename() + ".bz2")
783 except OSError:
784 os.unlink(l.getFilename())
785 # now make sure we can upgrade it
786 l.upgrade("upgrade")
787 self.failUnlessEqual(l.getText(),
788 "Some text\nSome more text\nmore\n")
789 self.failUnlessEqual(len(list(l.getChunks())), 2)
790 self.failIf(l.entries)
791
792 # now, do it again, but make it look like an upgraded 0.6.4 logfile
793 # (i.e. l.filename is missing, but the contents are there on disk)
794 l.entries = list(l.getChunks())
795 del l.filename
796 l.upgrade("upgrade")
797 self.failUnlessEqual(l.getText(),
798 "Some text\nSome more text\nmore\n")
799 self.failUnlessEqual(len(list(l.getChunks())), 2)
800 self.failIf(l.entries)
801 self.failUnless(l.hasContents())
802
803 def testHTMLUpgrade(self):
804 l = MyHTMLLog(self.basedir, "upgrade", "log contents")
805 l.upgrade("filename")
806
807 def testSubscribe(self):
808 l1 = MyLog(self.basedir, "subscribe1")
809 l1.finish()
810 self.failUnless(l1.isFinished())
811
812 s = MyLogSubscriber()
813 l1.subscribe(s, True)
814 l1.unsubscribe(s)
815 self.failIf(s.chunks)
816
817 s = MyLogSubscriber()
818 l1.subscribe(s, False)
819 l1.unsubscribe(s)
820 self.failIf(s.chunks)
821
822 finished = []
823 l2 = MyLog(self.basedir, "subscribe2")
824 l2.waitUntilFinished().addCallback(finished.append)
825 l2.addHeader("HEADER\n")
826 s1 = MyLogSubscriber()
827 l2.subscribe(s1, True)
828 s2 = MyLogSubscriber()
829 l2.subscribe(s2, False)
830 self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n")])
831 self.failUnlessEqual(s2.chunks, [])
832
833 l2.addStdout("Some text\n")
834 self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n"),
835 (builder.STDOUT, "Some text\n")])
836 self.failUnlessEqual(s2.chunks, [(builder.STDOUT, "Some text\n")])
837 l2.unsubscribe(s1)
838
839 l2.addStdout("Some more text\n")
840 self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n"),
841 (builder.STDOUT, "Some text\n")])
842 self.failUnlessEqual(s2.chunks, [(builder.STDOUT, "Some text\n"),
843 (builder.STDOUT, "Some more text\n"),
844 ])
845 self.failIf(finished)
846 l2.finish()
847 self.failUnlessEqual(finished, [l2])
848
849 def testConsumer(self):
850 l1 = MyLog(self.basedir, "consumer1")
851 l1.finish()
852 self.failUnless(l1.isFinished())
853
854 s = MyLogConsumer()
855 d = l1.subscribeConsumer(s)
856 d.addCallback(self._testConsumer_1, s)
857 return d
858 testConsumer.timeout = 5
859 def _testConsumer_1(self, res, s):
860 self.failIf(s.chunks)
861 self.failUnless(s.finished)
862 self.failIf(s.producer) # producer should be registered and removed
863
864 l2 = MyLog(self.basedir, "consumer2")
865 l2.addHeader("HEADER\n")
866 l2.finish()
867 self.failUnless(l2.isFinished())
868
869 s = MyLogConsumer()
870 d = l2.subscribeConsumer(s)
871 d.addCallback(self._testConsumer_2, s)
872 return d
873 def _testConsumer_2(self, res, s):
874 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")])
875 self.failUnless(s.finished)
876 self.failIf(s.producer) # producer should be registered and removed
877
878
879 l2 = MyLog(self.basedir, "consumer3")
880 l2.chunkSize = 1000
881 l2.addHeader("HEADER\n")
882 l2.addStdout(800*"a")
883 l2.addStdout(800*"a") # should now have two chunks on disk, 1000+600
884 l2.addStdout(800*"b") # HEADER,1000+600*a on disk, 800*a in memory
885 l2.addStdout(800*"b") # HEADER,1000+600*a,1000+600*b on disk
886 l2.addStdout(200*"c") # HEADER,1000+600*a,1000+600*b on disk,
887 # 200*c in memory
888
889 s = MyLogConsumer(limit=1)
890 d = l2.subscribeConsumer(s)
891 d.addCallback(self._testConsumer_3, l2, s)
892 return d
893 def _testConsumer_3(self, res, l2, s):
894 self.failUnless(s.streaming)
895 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")])
896 s.limit = 1
897 d = s.producer.resumeProducing()
898 d.addCallback(self._testConsumer_4, l2, s)
899 return d
900 def _testConsumer_4(self, res, l2, s):
901 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"),
902 (builder.STDOUT, 1000*"a"),
903 ])
904 s.limit = None
905 d = s.producer.resumeProducing()
906 d.addCallback(self._testConsumer_5, l2, s)
907 return d
908 def _testConsumer_5(self, res, l2, s):
909 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"),
910 (builder.STDOUT, 1000*"a"),
911 (builder.STDOUT, 600*"a"),
912 (builder.STDOUT, 1000*"b"),
913 (builder.STDOUT, 600*"b"),
914 (builder.STDOUT, 200*"c")])
915 l2.addStdout(1000*"c") # HEADER,1600*a,1600*b,1200*c on disk
916 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"),
917 (builder.STDOUT, 1000*"a"),
918 (builder.STDOUT, 600*"a"),
919 (builder.STDOUT, 1000*"b"),
920 (builder.STDOUT, 600*"b"),
921 (builder.STDOUT, 200*"c"),
922 (builder.STDOUT, 1000*"c")])
923 l2.finish()
924 self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"),
925 (builder.STDOUT, 1000*"a"),
926 (builder.STDOUT, 600*"a"),
927 (builder.STDOUT, 1000*"b"),
928 (builder.STDOUT, 600*"b"),
929 (builder.STDOUT, 200*"c"),
930 (builder.STDOUT, 1000*"c")])
931 self.failIf(s.producer)
932 self.failUnless(s.finished)
933
934 def testLargeSummary(self):
935 bigtext = "a" * 200000 # exceed the NetstringReceiver 100KB limit
936 l = MyLog(self.basedir, "large", bigtext)
937 s = MyLogConsumer()
938 d = l.subscribeConsumer(s)
939 def _check(res):
940 for ctype,chunk in s.chunks:
941 self.failUnless(len(chunk) < 100000)
942 merged = "".join([c[1] for c in s.chunks])
943 self.failUnless(merged == bigtext)
944 d.addCallback(_check)
945 # when this fails, it fails with a timeout, and there is an exception
946 # sent to log.err(). This AttributeError exception is in
947 # NetstringReceiver.dataReceived where it does
948 # self.transport.loseConnection() because of the NetstringParseError,
949 # however self.transport is None
950 return d
951 testLargeSummary.timeout = 5
952
953 def testLimit(self):
954 l = MyLog(self.basedir, "limit")
955 l.logMaxSize = 150
956 for i in range(1000):
957 l.addStdout("Some data")
958 l.finish()
959 t = l.getText()
960 # Compare against 175 since we truncate logs based on chunks, so we may
961 # go slightly over the limit
962 self.failIf(len(t) > 175, "Text too long (%i)" % len(t))
963 self.failUnless("truncated" in l.getTextWithHeaders(),
964 "No truncated message found")
965
966 class CompressLog(unittest.TestCase):
967 # compression is not supported unless bz2 is installed
968 try:
969 import bz2
970 except:
971 skip = "compression not supported (no bz2 module available)"
972
973 def testCompressLogs(self):
974 bss = setupBuildStepStatus("test-compress")
975 bss.build.builder.setLogCompressionLimit(1024)
976 l = bss.addLog('not-compress')
977 l.addStdout('a' * 512)
978 l.finish()
979 lc = bss.addLog('to-compress')
980 lc.addStdout('b' * 1024)
981 lc.finish()
982 d = bss.stepFinished(builder.SUCCESS)
983 self.failUnless(d is not None)
984 d.addCallback(self._verifyCompression, bss)
985 return d
986
987 def _verifyCompression(self, result, bss):
988 self.failUnless(len(bss.getLogs()), 2)
989 (ncl, cl) = bss.getLogs() # not compressed, compressed log
990 self.failUnless(os.path.isfile(ncl.getFilename()))
991 self.failIf(os.path.isfile(ncl.getFilename() + ".bz2"))
992 self.failIf(os.path.isfile(cl.getFilename()))
993 self.failUnless(os.path.isfile(cl.getFilename() + ".bz2"))
994 content = ncl.getText()
995 self.failUnless(len(content), 512)
996 content = cl.getText()
997 self.failUnless(len(content), 1024)
998 pass
999
1000 config_base = """
1001 from buildbot.process import factory
1002 from buildbot.steps import dummy
1003 from buildbot.buildslave import BuildSlave
1004 from buildbot.config import BuilderConfig
1005 s = factory.s
1006
1007 f1 = factory.QuickBuildFactory('fakerep', 'cvsmodule', configure=None)
1008
1009 f2 = factory.BuildFactory([
1010 s(dummy.Dummy, timeout=1),
1011 s(dummy.RemoteDummy, timeout=2),
1012 ])
1013
1014 BuildmasterConfig = c = {}
1015 c['slaves'] = [BuildSlave('bot1', 'sekrit')]
1016 c['schedulers'] = []
1017 c['builders'] = [
1018 BuilderConfig(name='quick', slavename='bot1', factory=f1),
1019 ]
1020 c['slavePortnum'] = 0
1021 """
1022
1023 config_2 = config_base + """
1024 c['builders'] = [
1025 BuilderConfig(name='dummy', slavename='bot1', factory=f2),
1026 BuilderConfig(name='testdummy', slavename='bot1',
1027 factory=f2, category='test'),
1028 ]
1029 """
1030
1031 class STarget(base.StatusReceiver):
1032 debug = False
1033
1034 def __init__(self, mode):
1035 self.mode = mode
1036 self.events = []
1037 def announce(self):
1038 if self.debug:
1039 print self.events[-1]
1040
1041 def builderAdded(self, name, builder):
1042 self.events.append(("builderAdded", name, builder))
1043 self.announce()
1044 if "builder" in self.mode:
1045 return self
1046 def builderChangedState(self, name, state):
1047 self.events.append(("builderChangedState", name, state))
1048 self.announce()
1049 def buildStarted(self, name, build):
1050 self.events.append(("buildStarted", name, build))
1051 self.announce()
1052 if "eta" in self.mode:
1053 self.eta_build = build.getETA()
1054 if "build" in self.mode:
1055 return self
1056 def buildETAUpdate(self, build, ETA):
1057 self.events.append(("buildETAUpdate", build, ETA))
1058 self.announce()
1059 def changeAdded(self, change):
1060 self.events.append(("changeAdded", change))
1061 self.announce()
1062 def stepStarted(self, build, step):
1063 self.events.append(("stepStarted", build, step))
1064 self.announce()
1065 if 0 and "eta" in self.mode:
1066 print "TIMES", step.getTimes()
1067 print "ETA", step.getETA()
1068 print "EXP", step.getExpectations()
1069 if "step" in self.mode:
1070 return self
1071 def stepTextChanged(self, build, step, text):
1072 self.events.append(("stepTextChanged", step, text))
1073 def stepText2Changed(self, build, step, text2):
1074 self.events.append(("stepText2Changed", step, text2))
1075 def stepETAUpdate(self, build, step, ETA, expectations):
1076 self.events.append(("stepETAUpdate", build, step, ETA, expectations))
1077 self.announce()
1078 def logStarted(self, build, step, log):
1079 self.events.append(("logStarted", build, step, log))
1080 self.announce()
1081 def logFinished(self, build, step, log):
1082 self.events.append(("logFinished", build, step, log))
1083 self.announce()
1084 def stepFinished(self, build, step, results):
1085 self.events.append(("stepFinished", build, step, results))
1086 if 0 and "eta" in self.mode:
1087 print "post-EXP", step.getExpectations()
1088 self.announce()
1089 def buildFinished(self, name, build, results):
1090 self.events.append(("buildFinished", name, build, results))
1091 self.announce()
1092 def builderRemoved(self, name):
1093 self.events.append(("builderRemoved", name))
1094 self.announce()
1095 def slaveConnected(self, name):
1096 self.events.append(("slaveConnected", name))
1097 self.announce()
1098 def slaveDisconnected(self, name):
1099 self.events.append(("slaveDisconnected", name))
1100 self.announce()
1101
1102 class VerifyChangeAdded(RunMixin, unittest.TestCase):
1103 def testChangeAdded(self):
1104 m = self.master
1105
1106 s = m.getStatus()
1107 self.t1 = t1 = STarget(["builder"])
1108 s.subscribe(t1)
1109
1110 m.loadConfig(config_2)
1111 m.readConfig = True
1112 m.startService()
1113
1114 cm = self.master.change_svc
1115 c = Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
1116 cm.addChange(c)
1117 self.failUnlessEqual(t1.events[-1], ("changeAdded", c))
1118
1119 class Subscription(RunMixin, unittest.TestCase):
1120 # verify that StatusTargets can subscribe/unsubscribe properly
1121
1122 def testSlave(self):
1123 m = self.master
1124 s = m.getStatus()
1125 self.t1 = t1 = STarget(["builder"])
1126 #t1.debug = True; print
1127 s.subscribe(t1)
1128 self.failUnlessEqual(len(t1.events), 0)
1129
1130 self.t3 = t3 = STarget(["builder", "build", "step"])
1131 s.subscribe(t3)
1132
1133 m.loadConfig(config_2)
1134 m.readConfig = True
1135 m.startService()
1136
1137 self.failUnlessEqual(len(t1.events), 4)
1138 self.failUnlessEqual(t1.events[0][0:2], ("builderAdded", "dummy"))
1139 self.failUnlessEqual(t1.events[1],
1140 ("builderChangedState", "dummy", "offline"))
1141 self.failUnlessEqual(t1.events[2][0:2], ("builderAdded", "testdummy"))
1142 self.failUnlessEqual(t1.events[3],
1143 ("builderChangedState", "testdummy", "offline"))
1144 t1.events = []
1145
1146 self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"])
1147 self.failUnlessEqual(s.getBuilderNames(categories=['test']),
1148 ["testdummy"])
1149 self.s1 = s1 = s.getBuilder("dummy")
1150 self.failUnlessEqual(s1.getName(), "dummy")
1151 self.failUnlessEqual(s1.getState(), ("offline", []))
1152 self.failUnlessEqual(s1.getCurrentBuilds(), [])
1153 self.failUnlessEqual(s1.getLastFinishedBuild(), None)
1154 self.failUnlessEqual(s1.getBuild(-1), None)
1155 #self.failUnlessEqual(s1.getEvent(-1), foo("created"))
1156
1157 # status targets should, upon being subscribed, immediately get a
1158 # list of all current builders matching their category
1159 self.t2 = t2 = STarget([])
1160 s.subscribe(t2)
1161 self.failUnlessEqual(len(t2.events), 2)
1162 self.failUnlessEqual(t2.events[0][0:2], ("builderAdded", "dummy"))
1163 self.failUnlessEqual(t2.events[1][0:2], ("builderAdded", "testdummy"))
1164
1165 d = self.connectSlave(builders=["dummy", "testdummy"])
1166 d.addCallback(self._testSlave_1, t1)
1167 return d
1168
1169 def _testSlave_1(self, res, t1):
1170 self.failUnlessEqual(len(t1.events), 3)
1171 self.failUnlessEqual(t1.events[0],
1172 ("slaveConnected", "bot1"))
1173 self.failUnlessEqual(t1.events[1],
1174 ("builderChangedState", "dummy", "idle"))
1175 self.failUnlessEqual(t1.events[2],
1176 ("builderChangedState", "testdummy", "idle"))
1177 t1.events = []
1178
1179 c = interfaces.IControl(self.master)
1180 req = BuildRequest("forced build for testing", SourceStamp(), 'test_buil der')
1181 c.getBuilder("dummy").requestBuild(req)
1182 d = req.waitUntilFinished()
1183 d2 = self.master.botmaster.waitUntilBuilderIdle("dummy")
1184 dl = defer.DeferredList([d, d2])
1185 dl.addCallback(self._testSlave_2)
1186 return dl
1187
1188 def _testSlave_2(self, res):
1189 # t1 subscribes to builds, but not anything lower-level
1190 ev = self.t1.events
1191 self.failUnlessEqual(len(ev), 4)
1192 self.failUnlessEqual(ev[0][0:3],
1193 ("builderChangedState", "dummy", "building"))
1194 self.failUnlessEqual(ev[1][0], "buildStarted")
1195 self.failUnlessEqual(ev[2][0:2]+ev[2][3:4],
1196 ("buildFinished", "dummy", builder.SUCCESS))
1197 self.failUnlessEqual(ev[3][0:3],
1198 ("builderChangedState", "dummy", "idle"))
1199
1200 self.failUnlessEqual([ev[0] for ev in self.t3.events],
1201 ["builderAdded",
1202 "builderChangedState", # offline
1203 "builderAdded",
1204 "builderChangedState", # idle
1205 "slaveConnected",
1206 "builderChangedState", # offline
1207 "builderChangedState", # idle
1208 "builderChangedState", # building
1209 "buildStarted",
1210 "stepStarted", "stepETAUpdate",
1211 "stepTextChanged", "stepFinished",
1212 "stepStarted", "stepETAUpdate",
1213 "stepTextChanged", "logStarted", "logFinished",
1214 "stepTextChanged", "stepText2Changed",
1215 "stepFinished",
1216 "buildFinished",
1217 "builderChangedState", # idle
1218 ])
1219
1220 b = self.s1.getLastFinishedBuild()
1221 self.failUnless(b)
1222 self.failUnlessEqual(b.getBuilder().getName(), "dummy")
1223 self.failUnlessEqual(b.getNumber(), 0)
1224 self.failUnlessEqual(b.getSourceStamp().branch, None)
1225 self.failUnlessEqual(b.getSourceStamp().patch, None)
1226 self.failUnlessEqual(b.getSourceStamp().revision, None)
1227 self.failUnlessEqual(b.getReason(), "forced build for testing")
1228 self.failUnlessEqual(b.getChanges(), ())
1229 self.failUnlessEqual(b.getResponsibleUsers(), [])
1230 self.failUnless(b.isFinished())
1231 self.failUnlessEqual(b.getText(), ['build', 'successful'])
1232 self.failUnlessEqual(b.getResults(), builder.SUCCESS)
1233
1234 steps = b.getSteps()
1235 self.failUnlessEqual(len(steps), 2)
1236
1237 eta = 0
1238 st1 = steps[0]
1239 self.failUnlessEqual(st1.getName(), "dummy")
1240 self.failUnless(st1.isFinished())
1241 self.failUnlessEqual(st1.getText(), ["delay", "1 secs"])
1242 start,finish = st1.getTimes()
1243 self.failUnless(0.5 < (finish-start) < 10)
1244 self.failUnlessEqual(st1.getExpectations(), [])
1245 self.failUnlessEqual(st1.getLogs(), [])
1246 eta += finish-start
1247
1248 st2 = steps[1]
1249 self.failUnlessEqual(st2.getName(), "remote dummy")
1250 self.failUnless(st2.isFinished())
1251 self.failUnlessEqual(st2.getText(),
1252 ["remote", "delay", "2 secs"])
1253 start,finish = st2.getTimes()
1254 self.failUnless(1.5 < (finish-start) < 10)
1255 eta += finish-start
1256 self.failUnlessEqual(st2.getExpectations(), [('output', 38, None)])
1257 logs = st2.getLogs()
1258 self.failUnlessEqual(len(logs), 1)
1259 self.failUnlessEqual(logs[0].getName(), "stdio")
1260 self.failUnlessEqual(logs[0].getText(), "data")
1261
1262 self.eta = eta
1263 # now we run it a second time, and we should have an ETA
1264
1265 self.t4 = t4 = STarget(["builder", "build", "eta"])
1266 self.master.getStatus().subscribe(t4)
1267 c = interfaces.IControl(self.master)
1268 req = BuildRequest("forced build for testing", SourceStamp(), 'test_buil der')
1269 c.getBuilder("dummy").requestBuild(req)
1270 d = req.waitUntilFinished()
1271 d2 = self.master.botmaster.waitUntilBuilderIdle("dummy")
1272 dl = defer.DeferredList([d, d2])
1273 dl.addCallback(lambda ign: self.shutdownAllSlaves())
1274 dl.addCallback(self._testSlave_3)
1275 return dl
1276
1277 def _testSlave_3(self, res):
1278 t4 = self.t4
1279 eta = self.eta
1280 self.failUnless(eta-1 < t4.eta_build < eta+1, # should be 3 seconds
1281 "t4.eta_build was %g, not in (%g,%g)"
1282 % (t4.eta_build, eta-1, eta+1))
1283
1284 self.failUnlessEqual([ev[0] for ev in self.t4.events],
1285 ["builderAdded",
1286 "builderChangedState", # offline
1287 "builderAdded",
1288 "builderChangedState", # idle
1289 "builderChangedState", # building
1290 "buildStarted",
1291 "stepStarted", "stepFinished",
1292 "stepStarted", "stepFinished",
1293 "buildFinished",
1294 "builderChangedState",
1295 "slaveDisconnected",
1296 "builderChangedState",
1297 "builderChangedState",
1298 ])
1299
1300 class Client(unittest.TestCase):
1301 def testAdaptation(self):
1302 b = builder.BuilderStatus("bname")
1303 b2 = client.makeRemote(b)
1304 self.failUnless(isinstance(b2, client.RemoteBuilder))
1305 b3 = client.makeRemote(None)
1306 self.failUnless(b3 is None)
1307
1308
1309 class ContactTester(unittest.TestCase):
1310 def test_notify_invalid_syntax(self):
1311 irc = MyContact()
1312 self.assertRaises(words.UsageError, lambda args, who: irc.command_NOTIFY (args, who), "", "mynick")
1313
1314 def test_notify_list(self):
1315 irc = MyContact()
1316 irc.command_NOTIFY("list", "mynick")
1317 self.failUnlessEqual(irc.message, "The following events are being notifi ed: []", "empty notify list")
1318
1319 irc.message = ""
1320 irc.command_NOTIFY("on started", "mynick")
1321 self.failUnlessEqual(irc.message, "The following events are being notifi ed: ['started']", "on started")
1322
1323 irc.message = ""
1324 irc.command_NOTIFY("on finished", "mynick")
1325 self.failUnlessEqual(irc.message, "The following events are being notifi ed: ['started', 'finished']", "on finished")
1326
1327 irc.message = ""
1328 irc.command_NOTIFY("off", "mynick")
1329 self.failUnlessEqual(irc.message, "The following events are being notifi ed: []", "off all")
1330
1331 irc.message = ""
1332 irc.command_NOTIFY("on", "mynick")
1333 self.failUnlessEqual(irc.message, "The following events are being notifi ed: ['started', 'finished']", "on default set")
1334
1335 irc.message = ""
1336 irc.command_NOTIFY("off started", "mynick")
1337 self.failUnlessEqual(irc.message, "The following events are being notifi ed: ['finished']", "off started")
1338
1339 irc.message = ""
1340 irc.command_NOTIFY("on success failure exception", "mynick")
1341 self.failUnlessEqual(irc.message, "The following events are being notifi ed: ['failure', 'finished', 'exception', 'success']", "on multiple events")
1342
1343 def test_notification_default(self):
1344 irc = MyContact()
1345
1346 my_builder = MyBuilder("builder78")
1347 my_build = MyIrcBuild(my_builder, 23, builder.SUCCESS)
1348
1349 irc.buildStarted(my_builder.getName(), my_build)
1350 self.failUnlessEqual(irc.message, "", "No notification with default sett ings")
1351
1352 irc.buildFinished(my_builder.getName(), my_build, None)
1353 self.failUnlessEqual(irc.message, "", "No notification with default sett ings")
1354
1355 def test_notification_started(self):
1356 irc = MyContact()
1357
1358 my_builder = MyBuilder("builder78")
1359 my_build = MyIrcBuild(my_builder, 23, builder.SUCCESS)
1360 my_build.changes = (
1361 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 123),
1362 Change(who = 'author2', files = ['file2'], comments = 'comment2', re vision = 456),
1363 )
1364
1365 irc.command_NOTIFY("on started", "mynick")
1366
1367 irc.message = ""
1368 irc.buildStarted(my_builder.getName(), my_build)
1369 self.failUnlessEqual(irc.message, "build #23 of builder78 started includ ing [123, 456]", "Start notification generated with notify_events=['started']")
1370
1371 irc.message = ""
1372 irc.buildFinished(my_builder.getName(), my_build, None)
1373 self.failUnlessEqual(irc.message, "", "No finished notification with not ify_events=['started']")
1374
1375 def test_notification_finished(self):
1376 irc = MyContact()
1377
1378 my_builder = MyBuilder("builder834")
1379 my_build = MyIrcBuild(my_builder, 862, builder.SUCCESS)
1380 my_build.changes = (
1381 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1382 )
1383
1384 irc.command_NOTIFY("on finished", "mynick")
1385
1386 irc.message = ""
1387 irc.buildStarted(my_builder.getName(), my_build)
1388 self.failUnlessEqual(irc.message, "", "No started notification with noti fy_events=['finished']")
1389
1390 irc.message = ""
1391 irc.buildFinished(my_builder.getName(), my_build, None)
1392 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated with notify_events=['finished']")
1393
1394 def test_notification_success(self):
1395 irc = MyContact()
1396
1397 my_builder = MyBuilder("builder834")
1398 my_build = MyIrcBuild(my_builder, 862, builder.SUCCESS)
1399 my_build.changes = (
1400 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1401 )
1402
1403 irc.command_NOTIFY("on success", "mynick")
1404
1405 irc.message = ""
1406 irc.buildStarted(my_builder.getName(), my_build)
1407 self.failUnlessEqual(irc.message, "", "No started notification with noti fy_events=['success']")
1408
1409 irc.message = ""
1410 irc.buildFinished(my_builder.getName(), my_build, None)
1411 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated on success with notify_events=['success']")
1412
1413 irc.message = ""
1414 my_build.results = builder.FAILURE
1415 irc.buildFinished(my_builder.getName(), my_build, None)
1416 self.failUnlessEqual(irc.message, "", "No finish notification generated on failure with notify_events=['success']")
1417
1418 irc.message = ""
1419 my_build.results = builder.EXCEPTION
1420 irc.buildFinished(my_builder.getName(), my_build, None)
1421 self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['success']")
1422
1423 def test_notification_failed(self):
1424 irc = MyContact()
1425
1426 my_builder = MyBuilder("builder834")
1427 my_build = MyIrcBuild(my_builder, 862, builder.FAILURE)
1428 my_build.changes = (
1429 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1430 )
1431
1432 irc.command_NOTIFY("on failure", "mynick")
1433
1434 irc.message = ""
1435 irc.buildStarted(my_builder.getName(), my_build)
1436 self.failUnlessEqual(irc.message, "", "No started notification with noti fy_events=['failed']")
1437
1438 irc.message = ""
1439 irc.channel.showBlameList = True
1440 irc.buildFinished(my_builder.getName(), my_build, None)
1441 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Failure [step1 step2] Build details are at http://myserver/mypath?build=765 b lamelist: author1", "Finish notification generated on failure with notify_events =['failed']")
1442 irc.channel.showBlameList = False
1443
1444 irc.message = ""
1445 my_build.results = builder.SUCCESS
1446 irc.buildFinished(my_builder.getName(), my_build, None)
1447 self.failUnlessEqual(irc.message, "", "No finish notification generated on success with notify_events=['failed']")
1448
1449 irc.message = ""
1450 my_build.results = builder.EXCEPTION
1451 irc.buildFinished(my_builder.getName(), my_build, None)
1452 self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['failed']")
1453
1454 def test_notification_exception(self):
1455 irc = MyContact()
1456
1457 my_builder = MyBuilder("builder834")
1458 my_build = MyIrcBuild(my_builder, 862, builder.EXCEPTION)
1459 my_build.changes = (
1460 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1461 )
1462
1463 irc.command_NOTIFY("on exception", "mynick")
1464
1465 irc.message = ""
1466 irc.buildStarted(my_builder.getName(), my_build)
1467 self.failUnlessEqual(irc.message, "", "No started notification with noti fy_events=['exception']")
1468
1469 irc.message = ""
1470 irc.buildFinished(my_builder.getName(), my_build, None)
1471 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypath?build=765" , "Finish notification generated on failure with notify_events=['exception']")
1472
1473 irc.message = ""
1474 irc.channel.showBlameList = True
1475 irc.buildFinished(my_builder.getName(), my_build, None)
1476 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypath?build=765 blamelist: author1", "Finish notification generated on failure with notify_even ts=['exception']")
1477 irc.channel.showBlameList = False
1478
1479 irc.message = ""
1480 my_build.results = builder.SUCCESS
1481 irc.buildFinished(my_builder.getName(), my_build, None)
1482 self.failUnlessEqual(irc.message, "", "No finish notification generated on success with notify_events=['exception']")
1483
1484 irc.message = ""
1485 my_build.results = builder.FAILURE
1486 irc.buildFinished(my_builder.getName(), my_build, None)
1487 self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['exception']")
1488
1489 def do_x_to_y_notification_test(self, notify, previous_result, new_result, e xpected_msg):
1490 irc = MyContact()
1491 irc.command_NOTIFY("on %s" % notify, "mynick")
1492
1493 my_builder = MyBuilder("builder834")
1494 my_build = MyIrcBuild(my_builder, 862, builder.FAILURE)
1495 my_build.changes = (
1496 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1497 )
1498
1499 previous_build = MyIrcBuild(my_builder, 861, previous_result)
1500 my_build.setPreviousBuild(previous_build)
1501
1502 irc.message = ""
1503 my_build.results = new_result
1504 irc.buildFinished(my_builder.getName(), my_build, None)
1505 self.failUnlessEqual(irc.message, expected_msg, "Finish notification gen erated on failure with notify_events=['successToFailure']")
1506
1507 def test_notification_successToFailure(self):
1508 self.do_x_to_y_notification_test(notify="successToFailure", previous_res ult=builder.SUCCESS, new_result=builder.FAILURE,
1509 expected_msg="build #862 of builder834 is complete: Failure [step1 step2] Build details are at http://myserver/mypath? build=765" )
1510
1511 self.do_x_to_y_notification_test(notify="successToFailure", previous_res ult=builder.SUCCESS, new_result=builder.SUCCESS,
1512 expected_msg = "" )
1513
1514 self.do_x_to_y_notification_test(notify="successToFailure", previous_res ult=builder.SUCCESS, new_result=builder.WARNINGS,
1515 expected_msg = "" )
1516
1517 self.do_x_to_y_notification_test(notify="successToFailure", previous_res ult=builder.SUCCESS, new_result=builder.EXCEPTION,
1518 expected_msg = "" )
1519
1520 def test_notification_successToWarnings(self):
1521 self.do_x_to_y_notification_test(notify="successToWarnings", previous_re sult=builder.SUCCESS, new_result=builder.WARNINGS,
1522 expected_msg="build #862 of builder834 is complete: Warnings [step1 step2] Build details are at http://myserver/mypath ?build=765" )
1523
1524 self.do_x_to_y_notification_test(notify="successToWarnings", previous_re sult=builder.SUCCESS, new_result=builder.SUCCESS,
1525 expected_msg = "" )
1526
1527 self.do_x_to_y_notification_test(notify="successToWarnings", previous_re sult=builder.SUCCESS, new_result=builder.FAILURE,
1528 expected_msg = "" )
1529
1530 self.do_x_to_y_notification_test(notify="successToWarnings", previous_re sult=builder.SUCCESS, new_result=builder.EXCEPTION,
1531 expected_msg = "" )
1532
1533 def test_notification_successToException(self):
1534 self.do_x_to_y_notification_test(notify="successToException", previous_r esult=builder.SUCCESS, new_result=builder.EXCEPTION,
1535 expected_msg="build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypat h?build=765" )
1536
1537 self.do_x_to_y_notification_test(notify="successToException", previous_r esult=builder.SUCCESS, new_result=builder.SUCCESS,
1538 expected_msg = "" )
1539
1540 self.do_x_to_y_notification_test(notify="successToException", previous_r esult=builder.SUCCESS, new_result=builder.FAILURE,
1541 expected_msg = "" )
1542
1543 self.do_x_to_y_notification_test(notify="successToException", previous_r esult=builder.SUCCESS, new_result=builder.WARNINGS,
1544 expected_msg = "" )
1545
1546
1547
1548
1549
1550 def test_notification_failureToSuccess(self):
1551 self.do_x_to_y_notification_test(notify="failureToSuccess", previous_res ult=builder.FAILURE,new_result=builder.SUCCESS,
1552 expected_msg="build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath? build=765" )
1553
1554 self.do_x_to_y_notification_test(notify="failureToSuccess", previous_res ult=builder.FAILURE,new_result=builder.FAILURE,
1555 expected_msg = "" )
1556
1557 self.do_x_to_y_notification_test(notify="failureToSuccess", previous_res ult=builder.FAILURE,new_result=builder.WARNINGS,
1558 expected_msg = "" )
1559
1560 self.do_x_to_y_notification_test(notify="failureToSuccess", previous_res ult=builder.FAILURE,new_result=builder.EXCEPTION,
1561 expected_msg = "" )
1562
1563 def test_notification_failureToWarnings(self):
1564 self.do_x_to_y_notification_test(notify="failureToWarnings", previous_re sult=builder.FAILURE, new_result=builder.WARNINGS,
1565 expected_msg="build #862 of builder834 is complete: Warnings [step1 step2] Build details are at http://myserver/mypath ?build=765" )
1566
1567 self.do_x_to_y_notification_test(notify="failureToWarnings", previous_re sult=builder.FAILURE, new_result=builder.SUCCESS,
1568 expected_msg = "" )
1569
1570 self.do_x_to_y_notification_test(notify="failureToWarnings", previous_re sult=builder.FAILURE, new_result=builder.FAILURE,
1571 expected_msg = "" )
1572
1573 self.do_x_to_y_notification_test(notify="failureToWarnings", previous_re sult=builder.FAILURE, new_result=builder.EXCEPTION,
1574 expected_msg = "" )
1575
1576 def test_notification_failureToException(self):
1577 self.do_x_to_y_notification_test(notify="failureToException", previous_r esult=builder.FAILURE, new_result=builder.EXCEPTION,
1578 expected_msg="build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypat h?build=765" )
1579
1580 self.do_x_to_y_notification_test(notify="failureToException", previous_r esult=builder.FAILURE, new_result=builder.SUCCESS,
1581 expected_msg = "" )
1582
1583 self.do_x_to_y_notification_test(notify="failureToException", previous_r esult=builder.FAILURE, new_result=builder.FAILURE,
1584 expected_msg = "" )
1585
1586 self.do_x_to_y_notification_test(notify="failureToException", previous_r esult=builder.FAILURE, new_result=builder.WARNINGS,
1587 expected_msg = "" )
1588
1589
1590
1591
1592
1593 def test_notification_warningsToFailure(self):
1594 self.do_x_to_y_notification_test(notify="warningsToFailure", previous_re sult=builder.WARNINGS, new_result=builder.FAILURE,
1595 expected_msg="build #862 of builder834 is complete: Failure [step1 step2] Build details are at http://myserver/mypath? build=765" )
1596
1597 self.do_x_to_y_notification_test(notify="warningsToFailure", previous_re sult=builder.WARNINGS, new_result=builder.SUCCESS,
1598 expected_msg = "" )
1599
1600 self.do_x_to_y_notification_test(notify="warningsToFailure", previous_re sult=builder.WARNINGS, new_result=builder.WARNINGS,
1601 expected_msg = "" )
1602
1603 self.do_x_to_y_notification_test(notify="warningsToFailure", previous_re sult=builder.WARNINGS, new_result=builder.EXCEPTION,
1604 expected_msg = "" )
1605
1606 def test_notification_warningsToSuccess(self):
1607 self.do_x_to_y_notification_test(notify="warningsToSuccess", previous_re sult=builder.WARNINGS, new_result=builder.SUCCESS,
1608 expected_msg="build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath? build=765" )
1609
1610 self.do_x_to_y_notification_test(notify="warningsToSuccess", previous_re sult=builder.WARNINGS, new_result=builder.WARNINGS,
1611 expected_msg = "" )
1612
1613 self.do_x_to_y_notification_test(notify="warningsToSuccess", previous_re sult=builder.WARNINGS, new_result=builder.FAILURE,
1614 expected_msg = "" )
1615
1616 self.do_x_to_y_notification_test(notify="warningsToSuccess", previous_re sult=builder.WARNINGS, new_result=builder.EXCEPTION,
1617 expected_msg = "" )
1618
1619 def test_notification_warningsToException(self):
1620 self.do_x_to_y_notification_test(notify="warningsToException", previous_ result=builder.WARNINGS, new_result=builder.EXCEPTION,
1621 expected_msg="build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypat h?build=765" )
1622
1623 self.do_x_to_y_notification_test(notify="warningsToException", previous_ result=builder.WARNINGS, new_result=builder.SUCCESS,
1624 expected_msg = "" )
1625
1626 self.do_x_to_y_notification_test(notify="warningsToException", previous_ result=builder.WARNINGS, new_result=builder.FAILURE,
1627 expected_msg = "" )
1628
1629 self.do_x_to_y_notification_test(notify="warningsToException", previous_ result=builder.WARNINGS, new_result=builder.WARNINGS,
1630 expected_msg = "" )
1631
1632
1633
1634
1635 def test_notification_exceptionToFailure(self):
1636 self.do_x_to_y_notification_test(notify="exceptionToFailure", previous_r esult=builder.EXCEPTION, new_result=builder.FAILURE,
1637 expected_msg="build #862 of builder834 is complete: Failure [step1 step2] Build details are at http://myserver/mypath? build=765" )
1638
1639 self.do_x_to_y_notification_test(notify="exceptionToFailure", previous_r esult=builder.EXCEPTION, new_result=builder.SUCCESS,
1640 expected_msg = "" )
1641
1642 self.do_x_to_y_notification_test(notify="exceptionToFailure", previous_r esult=builder.EXCEPTION, new_result=builder.WARNINGS,
1643 expected_msg = "" )
1644
1645 self.do_x_to_y_notification_test(notify="exceptionToFailure", previous_r esult=builder.EXCEPTION, new_result=builder.EXCEPTION,
1646 expected_msg = "" )
1647
1648 def test_notification_exceptionToWarnings(self):
1649 self.do_x_to_y_notification_test(notify="exceptionToWarnings", previous_ result=builder.EXCEPTION, new_result=builder.WARNINGS,
1650 expected_msg="build #862 of builder834 is complete: Warnings [step1 step2] Build details are at http://myserver/mypath ?build=765" )
1651
1652 self.do_x_to_y_notification_test(notify="exceptionToWarnings", previous_ result=builder.EXCEPTION, new_result=builder.SUCCESS,
1653 expected_msg = "" )
1654
1655 self.do_x_to_y_notification_test(notify="exceptionToWarnings", previous_ result=builder.EXCEPTION, new_result=builder.FAILURE,
1656 expected_msg = "" )
1657
1658 self.do_x_to_y_notification_test(notify="exceptionToWarnings", previous_ result=builder.EXCEPTION, new_result=builder.EXCEPTION,
1659 expected_msg = "" )
1660
1661 def test_notification_exceptionToSuccess(self):
1662 self.do_x_to_y_notification_test(notify="exceptionToSuccess", previous_r esult=builder.EXCEPTION, new_result=builder.SUCCESS,
1663 expected_msg="build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath? build=765" )
1664
1665 self.do_x_to_y_notification_test(notify="exceptionToSuccess", previous_r esult=builder.EXCEPTION, new_result=builder.EXCEPTION,
1666 expected_msg = "" )
1667
1668 self.do_x_to_y_notification_test(notify="exceptionToSuccess", previous_r esult=builder.EXCEPTION, new_result=builder.FAILURE,
1669 expected_msg = "" )
1670
1671 self.do_x_to_y_notification_test(notify="exceptionToSuccess", previous_r esult=builder.EXCEPTION, new_result=builder.WARNINGS,
1672 expected_msg = "" )
1673
1674 def test_notification_set_in_config(self):
1675 irc = MyContact(channel = MyChannel(notify_events = {'success': 1}))
1676
1677 my_builder = MyBuilder("builder834")
1678 my_build = MyIrcBuild(my_builder, 862, builder.SUCCESS)
1679 my_build.changes = (
1680 Change(who = 'author1', files = ['file1'], comments = 'comment1', re vision = 943),
1681 )
1682
1683 irc.message = ""
1684 irc.buildFinished(my_builder.getName(), my_build, None)
1685 self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated on success with notify_events=['success']")
1686
1687 class MyIrcBuild(builder.BuildStatus):
1688 results = None
1689
1690 def __init__(self, parent, number, results):
1691 builder.BuildStatus.__init__(self, parent, number)
1692 self.results = results
1693 self.previousBuild = None
1694
1695 def getResults(self):
1696 return self.results
1697
1698 def getText(self):
1699 return ('step1', 'step2')
1700
1701 def setPreviousBuild(self, pb):
1702 self.previousBuild = pb
1703
1704 def getPreviousBuild(self):
1705 return self.previousBuild
1706
1707 class URLProducer:
1708 def getURLForThing(self, build):
1709 return 'http://myserver/mypath?build=765'
1710
1711 class MyChannel:
1712 categories = None
1713 status = URLProducer()
1714 notify_events = {}
1715
1716 def __init__(self, notify_events = {}):
1717 self.notify_events = notify_events
1718 self.showBlameList = False
1719
1720 class MyContact(words.Contact):
1721 message = ""
1722
1723 def __init__(self, channel = MyChannel()):
1724 words.Contact.__init__(self, channel)
1725 self.message = ""
1726
1727 def subscribe_to_build_events(self):
1728 pass
1729
1730 def unsubscribe_from_build_events(self):
1731 pass
1732
1733 def send(self, msg):
1734 self.message += msg
1735
1736 class MyIrcStatusBot(words.IrcStatusBot):
1737 def msg(self, dest, message):
1738 self.message = ['msg', dest, message]
1739
1740 def notice(self, dest, message):
1741 self.message = ['notice', dest, message]
1742
1743 class IrcStatusBotTester(unittest.TestCase):
1744 def testMsgOrNotice(self):
1745 channel = MyIrcStatusBot('alice', 'pa55w0od', ['#here'],
1746 builder.SUCCESS, None, {})
1747 channel.msgOrNotice('bob', 'hello')
1748 self.failUnlessEqual(channel.message, ['msg', 'bob', 'hello'])
1749
1750 channel.msgOrNotice('#here', 'hello')
1751 self.failUnlessEqual(channel.message, ['msg', '#here', 'hello'])
1752
1753 channel.noticeOnChannel = True
1754
1755 channel.msgOrNotice('bob', 'hello')
1756 self.failUnlessEqual(channel.message, ['msg', 'bob', 'hello'])
1757
1758 channel.msgOrNotice('#here', 'hello')
1759 self.failUnlessEqual(channel.message, ['notice', '#here', 'hello'])
1760
1761 class StepStatistics(unittest.TestCase):
1762 def testStepStatistics(self):
1763 status = builder.BuildStatus(builder.BuilderStatus("test"), 123)
1764 status.addStepWithName('step1')
1765 status.addStepWithName('step2')
1766 status.addStepWithName('step3')
1767 status.addStepWithName('step4')
1768
1769 steps = status.getSteps()
1770 (step1, step2, step3, step4) = steps
1771
1772 step1.setStatistic('test-prop', 1)
1773 step3.setStatistic('test-prop', 2)
1774 step4.setStatistic('test-prop', 4)
1775
1776 step1.setStatistic('other-prop', 27)
1777 # Just to have some other properties around
1778
1779 self.failUnlessEqual(step1.getStatistic('test-prop'), 1,
1780 'Retrieve an existing property')
1781 self.failUnlessEqual(step1.getStatistic('test-prop', 99), 1,
1782 "Don't default an existing property")
1783 self.failUnlessEqual(step2.getStatistic('test-prop', 99), 99,
1784 'Default a non-existant property')
1785
1786 self.failUnlessEqual(
1787 status.getSummaryStatistic('test-prop', operator.add), 7,
1788 'Sum property across the build')
1789
1790 self.failUnlessEqual(
1791 status.getSummaryStatistic('test-prop', operator.add, 13), 20,
1792 'Sum property across the build with initial value')
1793
1794 class BuildExpectation(unittest.TestCase):
1795 class MyBuilderStatus:
1796 implements(interfaces.IBuilderStatus)
1797
1798 def setSlavenames(self, slaveName):
1799 pass
1800
1801 class MyBuilder(Builder):
1802 def __init__(self, name):
1803 Builder.__init__(self, {
1804 'name': name,
1805 'builddir': '/tmp/somewhere',
1806 'slavebuilddir': '/tmp/somewhere_else',
1807 'factory': 'aFactory'
1808 }, BuildExpectation.MyBuilderStatus())
1809
1810 class MyBuild(Build):
1811 def __init__(self, b):
1812 self.builder = b
1813 self.remote = None
1814
1815 step1_progress = progress.StepProgress('step1', ['elapsed'])
1816 self.progress = progress.BuildProgress([step1_progress])
1817 step1_progress.setBuildProgress(self.progress)
1818
1819 step1_progress.start()
1820 sleep(1);
1821 step1_progress.finish()
1822
1823 self.deferred = defer.Deferred()
1824 self.locks = []
1825 self.build_status = builder.BuildStatus(b.builder_status, 1)
1826
1827
1828 def testBuildExpectation_BuildSuccess(self):
1829 b = BuildExpectation.MyBuilder("builder1")
1830 build = BuildExpectation.MyBuild(b)
1831
1832 build.buildFinished(['sometext'], builder.SUCCESS)
1833 self.failIfEqual(b.expectations.expectedBuildTime(), 0, 'Non-Zero expect ation for a failed build')
1834
1835 def testBuildExpectation_BuildFailure(self):
1836 b = BuildExpectation.MyBuilder("builder1")
1837 build = BuildExpectation.MyBuild(b)
1838
1839 build.buildFinished(['sometext'], builder.FAILURE)
1840 self.failUnlessEqual(b.expectations, None, 'Zero expectation for a faile d build')
1841
1842 class Pruning(unittest.TestCase):
1843 def runTest(self, files, buildHorizon, logHorizon):
1844 bstat = builder.BuilderStatus("foo")
1845 bstat.buildHorizon = buildHorizon
1846 bstat.logHorizon = logHorizon
1847 bstat.basedir = "prune-test"
1848
1849 rmtree(bstat.basedir)
1850 os.mkdir(bstat.basedir)
1851 for filename in files:
1852 open(os.path.join(bstat.basedir, filename), "w").write("TEST")
1853 bstat.determineNextBuildNumber()
1854
1855 bstat.prune()
1856
1857 remaining = os.listdir(bstat.basedir)
1858 remaining.sort()
1859 return remaining
1860
1861 files_base = [
1862 '10',
1863 '11',
1864 '12', '12-log-bar', '12-log-foo',
1865 '13', '13-log-foo',
1866 '14', '14-log-bar', '14-log-foo',
1867 ]
1868
1869 def test_rmlogs(self):
1870 remaining = self.runTest(self.files_base, 5, 2)
1871 self.failUnlessEqual(remaining, [
1872 '10',
1873 '11',
1874 '12',
1875 '13', '13-log-foo',
1876 '14', '14-log-bar', '14-log-foo',
1877 ])
1878
1879 def test_rmbuilds(self):
1880 remaining = self.runTest(self.files_base, 2, 0)
1881 self.failUnlessEqual(remaining, [
1882 '13', '13-log-foo',
1883 '14', '14-log-bar', '14-log-foo',
1884 ])
1885
1886 class EventGenerator(unittest.TestCase):
1887 def makeGenerator(self, reasons=[], minTime=0):
1888 b = MyBuilder("bname")
1889 b1 = b.newBuild()
1890 b1.setSourceStamp(SourceStamp(changes=[Change("foo", [], "")]))
1891 b1.buildStarted(b1, 1)
1892 b2 = b.newBuild()
1893 b2.setSourceStamp(SourceStamp(changes=[Change("bar", [], "")]))
1894 b2.buildStarted(b2, 2)
1895 return b.eventGenerator([], [], reasons, minTime)
1896
1897 def testEventGenerator_Unfiltered(self):
1898 gen = self.makeGenerator()
1899 self.failUnlessEqual(len([e for e in gen]), 2)
1900
1901 def testEventGenerator_Filtered(self):
1902 gen = self.makeGenerator(["foo"])
1903 self.failUnlessEqual(len([e for e in gen]), 1)
1904
1905 def testEventGenerator_MinTime(self):
1906 gen = self.makeGenerator([], 2)
1907 self.failUnlessEqual(len([e for e in gen]), 1)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698