Package buildbot :: Package process :: Module step_twisted2
[frames] | no frames]

Source Code for Module buildbot.process.step_twisted2

  1   
  2  from buildbot.status import tests 
  3  from buildbot.process.step import SUCCESS, FAILURE, BuildStep 
  4  from buildbot.process.step_twisted import RunUnitTests 
  5   
  6  from zope.interface import implements 
  7  from twisted.python import log, failure 
  8  from twisted.spread import jelly 
  9  from twisted.pb.tokens import BananaError 
 10  from twisted.web.html import PRE 
 11  from twisted.web.error import NoResource 
 12   
13 -class Null: pass
14 ResultTypes = Null() 15 ResultTypeNames = ["SKIP", 16 "EXPECTED_FAILURE", "FAILURE", "ERROR", 17 "UNEXPECTED_SUCCESS", "SUCCESS"] 18 try: 19 from twisted.trial import reporter # introduced in Twisted-1.0.5 20 # extract the individual result types 21 for name in ResultTypeNames: 22 setattr(ResultTypes, name, getattr(reporter, name)) 23 except ImportError: 24 from twisted.trial import unittest # Twisted-1.0.4 has them here 25 for name in ResultTypeNames: 26 setattr(ResultTypes, name, getattr(unittest, name)) 27 28 log._keepErrors = 0 29 from twisted.trial import remote # for trial/jelly parsing 30 31 import StringIO 32
33 -class OneJellyTest(tests.OneTest):
34 - def html(self, request):
35 tpl = "<HTML><BODY>\n\n%s\n\n</body></html>\n" 36 pptpl = "<HTML><BODY>\n\n<pre>%s</pre>\n\n</body></html>\n" 37 t = request.postpath[0] # one of 'short', 'long' #, or 'html' 38 if isinstance(self.results, failure.Failure): 39 # it would be nice to remove unittest functions from the 40 # traceback like unittest.format_exception() does. 41 if t == 'short': 42 s = StringIO.StringIO() 43 self.results.printTraceback(s) 44 return pptpl % PRE(s.getvalue()) 45 elif t == 'long': 46 s = StringIO.StringIO() 47 self.results.printDetailedTraceback(s) 48 return pptpl % PRE(s.getvalue()) 49 #elif t == 'html': 50 # return tpl % formatFailure(self.results) 51 # ACK! source lines aren't stored in the Failure, rather, 52 # formatFailure pulls them (by filename) from the local 53 # disk. Feh. Even printTraceback() won't work. Double feh. 54 return NoResource("No such mode '%s'" % t) 55 if self.results == None: 56 return tpl % "No results to show: test probably passed." 57 # maybe results are plain text? 58 return pptpl % PRE(self.results)
59
60 -class TwistedJellyTestResults(tests.TestResults):
61 oneTestClass = OneJellyTest
62 - def describeOneTest(self, testname):
63 return "%s: %s\n" % (testname, self.tests[testname][0])
64
65 -class RunUnitTestsJelly(RunUnitTests):
66 """I run the unit tests with the --jelly option, which generates 67 machine-parseable results as the tests are run. 68 """ 69 trialMode = "--jelly" 70 implements(remote.IRemoteReporter) 71 72 ourtypes = { ResultTypes.SKIP: tests.SKIP, 73 ResultTypes.EXPECTED_FAILURE: tests.EXPECTED_FAILURE, 74 ResultTypes.FAILURE: tests.FAILURE, 75 ResultTypes.ERROR: tests.ERROR, 76 ResultTypes.UNEXPECTED_SUCCESS: tests.UNEXPECTED_SUCCESS, 77 ResultTypes.SUCCESS: tests.SUCCESS, 78 } 79
80 - def start(self):
81 self.decoder = remote.DecodeReport(self) 82 # don't accept anything unpleasant from the (untrusted) build slave 83 # The jellied stream may have Failures, but everything inside should 84 # be a string 85 security = jelly.SecurityOptions() 86 security.allowBasicTypes() 87 security.allowInstancesOf(failure.Failure) 88 self.decoder.taster = security 89 self.results = TwistedJellyTestResults() 90 RunUnitTests.start(self)
91
92 - def logProgress(self, progress):
93 # XXX: track number of tests 94 BuildStep.logProgress(self, progress)
95
96 - def addStdout(self, data):
97 if not self.decoder: 98 return 99 try: 100 self.decoder.dataReceived(data) 101 except BananaError: 102 self.decoder = None 103 log.msg("trial --jelly output unparseable, traceback follows") 104 log.deferr()
105
106 - def remote_start(self, expectedTests, times=None):
107 print "remote_start", expectedTests
108 - def remote_reportImportError(self, name, aFailure, times=None):
109 pass
110 - def remote_reportStart(self, testClass, method, times=None):
111 print "reportStart", testClass, method
112
113 - def remote_reportResults(self, testClass, method, resultType, results, 114 times=None):
115 print "reportResults", testClass, method, resultType 116 which = testClass + "." + method 117 self.results.addTest(which, 118 self.ourtypes.get(resultType, tests.UNKNOWN), 119 results)
120
121 - def finished(self, rc):
122 # give self.results to our Build object 123 self.build.testsFinished(self.results) 124 total = self.results.countTests() 125 count = self.results.countFailures() 126 result = SUCCESS 127 if total == None: 128 result = (FAILURE, ['tests%s' % self.rtext(' (%s)')]) 129 if count: 130 result = (FAILURE, ["%d tes%s%s" % (count, 131 (count == 1 and 't' or 'ts'), 132 self.rtext(' (%s)'))]) 133 return self.stepComplete(result)
134 - def finishStatus(self, result):
135 total = self.results.countTests() 136 count = self.results.countFailures() 137 text = [] 138 if count == 0: 139 text.extend(["%d %s" % \ 140 (total, 141 total == 1 and "test" or "tests"), 142 "passed"]) 143 else: 144 text.append("tests") 145 text.append("%d %s" % \ 146 (count, 147 count == 1 and "failure" or "failures")) 148 self.updateCurrentActivity(text=text) 149 self.addFileToCurrentActivity("tests", self.results) 150 #self.finishStatusSummary() 151 self.finishCurrentActivity()
152