| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |