| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: buildbot.test.test_buildstep -*- | |
| 2 | |
| 3 # test cases for buildbot.process.buildstep | |
| 4 | |
| 5 from twisted.trial import unittest | |
| 6 | |
| 7 from buildbot import interfaces | |
| 8 from buildbot.process import buildstep | |
| 9 from buildbot.process import mtrlogobserver | |
| 10 from buildbot.process import subunitlogobserver | |
| 11 | |
| 12 # have to subclass LogObserver in order to test it, since the default | |
| 13 # implementations of outReceived() and errReceived() do nothing | |
| 14 class MyLogObserver(buildstep.LogObserver): | |
| 15 def __init__(self): | |
| 16 self._out = [] # list of chunks | |
| 17 self._err = [] | |
| 18 | |
| 19 def outReceived(self, data): | |
| 20 self._out.append(data) | |
| 21 | |
| 22 def errReceived(self, data): | |
| 23 self._err.append(data) | |
| 24 | |
| 25 class ObserverTestCase(unittest.TestCase): | |
| 26 observer_cls = None # must be set by subclass | |
| 27 | |
| 28 def setUp(self): | |
| 29 self.observer = self.observer_cls() | |
| 30 | |
| 31 def _logStdout(self, chunk): | |
| 32 # why does LogObserver.logChunk() take 'build', 'step', and | |
| 33 # 'log' arguments when it clearly doesn't use them for anything? | |
| 34 self.observer.logChunk(None, None, None, interfaces.LOG_CHANNEL_STDOUT,
chunk) | |
| 35 | |
| 36 def _logStderr(self, chunk): | |
| 37 self.observer.logChunk(None, None, None, interfaces.LOG_CHANNEL_STDERR,
chunk) | |
| 38 | |
| 39 def _assertStdout(self, expect_lines): | |
| 40 self.assertEqual(self.observer._out, expect_lines) | |
| 41 | |
| 42 def _assertStderr(self, expect_lines): | |
| 43 self.assertEqual(self.observer._err, expect_lines) | |
| 44 | |
| 45 class LogObserver(ObserverTestCase): | |
| 46 | |
| 47 observer_cls = MyLogObserver | |
| 48 | |
| 49 def testLogChunk(self): | |
| 50 self._logStdout("foo") | |
| 51 self._logStderr("argh") | |
| 52 self._logStdout(" wubba\n") | |
| 53 self._logStderr("!!!\n") | |
| 54 | |
| 55 self._assertStdout(["foo", " wubba\n"]) | |
| 56 self._assertStderr(["argh", "!!!\n"]) | |
| 57 | |
| 58 # again, have to subclass LogLineObserver in order to test it, because the | |
| 59 # default implementations of data-receiving methods are empty | |
| 60 class MyLogLineObserver(buildstep.LogLineObserver): | |
| 61 def __init__(self): | |
| 62 #super(MyLogLineObserver, self).__init__() | |
| 63 buildstep.LogLineObserver.__init__(self) | |
| 64 | |
| 65 self._out = [] # list of lines | |
| 66 self._err = [] | |
| 67 | |
| 68 def outLineReceived(self, line): | |
| 69 self._out.append(line) | |
| 70 | |
| 71 def errLineReceived(self, line): | |
| 72 self._err.append(line) | |
| 73 | |
| 74 class LogLineObserver(ObserverTestCase): | |
| 75 observer_cls = MyLogLineObserver | |
| 76 | |
| 77 def testLineBuffered(self): | |
| 78 # no challenge here: we feed it chunks that are already lines | |
| 79 # (like a program writing to stdout in line-buffered mode) | |
| 80 self._logStdout("stdout line 1\n") | |
| 81 self._logStdout("stdout line 2\n") | |
| 82 self._logStderr("stderr line 1\n") | |
| 83 self._logStdout("stdout line 3\n") | |
| 84 | |
| 85 self._assertStdout(["stdout line 1", | |
| 86 "stdout line 2", | |
| 87 "stdout line 3"]) | |
| 88 self._assertStderr(["stderr line 1"]) | |
| 89 | |
| 90 def testShortBrokenLines(self): | |
| 91 self._logStdout("stdout line 1 starts ") | |
| 92 self._logStderr("an intervening line of error\n") | |
| 93 self._logStdout("and continues ") | |
| 94 self._logStdout("but finishes here\n") | |
| 95 self._logStderr("more error\n") | |
| 96 self._logStdout("and another line of stdout\n") | |
| 97 | |
| 98 self._assertStdout(["stdout line 1 starts and continues but finishes her
e", | |
| 99 "and another line of stdout"]) | |
| 100 self._assertStderr(["an intervening line of error", | |
| 101 "more error"]) | |
| 102 | |
| 103 def testLongLine(self): | |
| 104 chunk = "." * 1024 | |
| 105 self._logStdout(chunk) | |
| 106 self._logStdout(chunk) | |
| 107 self._logStdout(chunk) | |
| 108 self._logStdout(chunk) | |
| 109 self._logStdout(chunk) | |
| 110 self._logStdout("\n") | |
| 111 | |
| 112 self._assertStdout([chunk * 5]) | |
| 113 self._assertStderr([]) | |
| 114 | |
| 115 def testBigChunk(self): | |
| 116 chunk = "." * 5000 | |
| 117 self._logStdout(chunk) | |
| 118 self._logStdout("\n") | |
| 119 | |
| 120 self._assertStdout([chunk]) | |
| 121 self._assertStderr([]) | |
| 122 | |
| 123 def testReallyLongLine(self): | |
| 124 # A single line of > 16384 bytes is dropped on the floor (bug #201). | |
| 125 # In real life, I observed such a line being broken into chunks of | |
| 126 # 4095 bytes, so that's how I'm breaking it here. | |
| 127 self.observer.setMaxLineLength(65536) | |
| 128 chunk = "." * 4095 | |
| 129 self._logStdout(chunk) | |
| 130 self._logStdout(chunk) | |
| 131 self._logStdout(chunk) | |
| 132 self._logStdout(chunk) # now we're up to 16380 bytes | |
| 133 self._logStdout("12345\n") | |
| 134 | |
| 135 self._assertStdout([chunk*4 + "12345"]) | |
| 136 self._assertStderr([]) | |
| 137 | |
| 138 class MyMtrLogObserver(mtrlogobserver.MtrLogObserver): | |
| 139 def __init__(self): | |
| 140 mtrlogobserver.MtrLogObserver.__init__(self, textLimit=3, testNameLimit=
15) | |
| 141 self.testFails = [] | |
| 142 self.testWarnLists = [] | |
| 143 # We don't have a buildstep in self.step. | |
| 144 # So we'll just install ourself there, so we can check the call of | |
| 145 # setProgress(). | |
| 146 # Same for self.step.step_status.setText() | |
| 147 self.step = self | |
| 148 self.step_status = self | |
| 149 self.progresses = [] | |
| 150 self.text = [] | |
| 151 | |
| 152 def setProgress(self, type, value): | |
| 153 self.progresses.append((type, value)) | |
| 154 | |
| 155 def setText(self, text): | |
| 156 self.text = text | |
| 157 | |
| 158 def collectTestFail(self, testname, variant, result, info, text): | |
| 159 self.testFails.append((testname, variant, result, info, text)) | |
| 160 | |
| 161 def collectWarningTests(self, testList): | |
| 162 self.testWarnLists.append(testList) | |
| 163 | |
| 164 class MtrLogObserver(ObserverTestCase): | |
| 165 observer_cls = MyMtrLogObserver | |
| 166 | |
| 167 def test1(self): | |
| 168 self._logStdout(""" | |
| 169 MySQL Version 5.1.35 | |
| 170 ============================================================================== | |
| 171 TEST RESULT TIME (ms) | |
| 172 ------------------------------------------------------------ | |
| 173 worker[3] Using MTR_BUILD_THREAD 252, with reserved ports 12520..12529 | |
| 174 binlog.binlog_multi_engine [ skipped ] No ndbcluster tests(--skip
-ndbcluster) | |
| 175 rpl.rpl_ssl 'row' [ pass ] 13976 | |
| 176 ***Warnings generated in error logs during shutdown after running tests: rpl.rpl
_ssl | |
| 177 rpl.rpl_ssl 'mix' [ pass ] 13308 | |
| 178 main.pool_of_threads w1 [ skipped ] Test requires: 'have_po
ol_of_threads' | |
| 179 ------------------------------------------------------------ | |
| 180 The servers were restarted 613 times | |
| 181 mysql-test-run: *** ERROR: There were errors/warnings in server logs after runni
ng test cases. | |
| 182 All 1002 tests were successful. | |
| 183 | |
| 184 Errors/warnings were found in logfiles during server shutdown after running the | |
| 185 following sequence(s) of tests: | |
| 186 rpl.rpl_ssl | |
| 187 """) | |
| 188 self.assertEqual(self.observer.progresses, | |
| 189 map((lambda (x): ('tests', x)), [1,2])) | |
| 190 self.assertEqual(self.observer.testWarnLists, [["rpl.rpl_ssl"]]) | |
| 191 self.assertEqual(self.observer.testFails, []) | |
| 192 self.assertEqual(self.observer.text[1:], ["W:rpl_ssl"]) | |
| 193 | |
| 194 def test2(self): | |
| 195 self._logStdout(""" | |
| 196 Logging: mysql-test-run.pl --force --skip-ndb | |
| 197 ============================================================================== | |
| 198 TEST RESULT TIME (ms) | |
| 199 ------------------------------------------------------------ | |
| 200 binlog.binlog_multi_engine [ skipped ] No ndbcluster tests(--skip
-ndbcluster) | |
| 201 rpl.rpl_sp 'mix' [ pass ] 8117 | |
| 202 | |
| 203 MTR's internal check of the test case 'rpl.rpl_sp' failed. | |
| 204 This is the diff of the states of the servers before and after the | |
| 205 test case was executed: | |
| 206 mysqltest: Logging to '/home/archivist/archivist-cnc/archivist-cnc/build/mysql-t
est/var/tmp/check-mysqld_2.log'. | |
| 207 --- /home/archivist/archivist-cnc/archivist-cnc/build/mysql-test/var/tmp/check-m
ysqld_2.result 2009-06-18 16:49:19.000000000 +0300 | |
| 208 +++ /home/archivist/archivist-cnc/archivist-cnc/build/mysql-test/var/tmp/check-m
ysqld_2.reject 2009-06-18 16:49:29.000000000 +0300 | |
| 209 @@ -523,7 +523,7 @@ | |
| 210 mysql.help_keyword 864336512 | |
| 211 mysql.help_relation 2554468794 | |
| 212 mysql.host 0 | |
| 213 -mysql.proc 3342691386 | |
| 214 +mysql.proc 3520745907 | |
| 215 | |
| 216 not ok | |
| 217 | |
| 218 rpl.rpl_sp_effects 'row' [ pass ] 3789 | |
| 219 rpl.rpl_temporary_errors 'mix' w2 [ fail ] | |
| 220 Test ended at 2009-06-18 16:21:28 | |
| 221 | |
| 222 CURRENT_TEST: rpl.rpl_temporary_errors | |
| 223 Retrying test, attempt(2/3)... | |
| 224 | |
| 225 ***Warnings generated in error logs during shutdown after running tests: rpl.rpl
_temporary_errors | |
| 226 rpl.rpl_temporary_errors 'mix' [ retry-pass ] 2108 | |
| 227 rpl.rpl_trunc_temp 'stmt' [ pass ] 2576 | |
| 228 main.information_schema [ pass ] 106092 | |
| 229 timer 5953: expired after 900 seconds | |
| 230 worker[1] Trying to dump core for [mysqltest - pid: 5975, winpid: 5975] | |
| 231 main.information_schema_all_engines [ fail ] timeout after 900 seconds | |
| 232 Test ended at 2009-06-18 18:37:25 | |
| 233 Retrying test, attempt(2/3)... | |
| 234 | |
| 235 ***Warnings generated in error logs during shutdown after running tests: main.ha
ndler_myisam main.ctype_ujis_ucs2 main.ctype_recoding | |
| 236 main.information_schema_chmod [ pass ] 84 | |
| 237 rpl.rpl_circular_for_4_hosts 'stmt' [ pass ] 344547 | |
| 238 timer 21612: expired after 21600 seconds | |
| 239 Test suite timeout! Terminating... | |
| 240 mysql-test-run: *** ERROR: Not all tests completed | |
| 241 """) | |
| 242 self.assertEqual(self.observer.progresses, | |
| 243 map((lambda (x): ('tests', x)), [1,2,3,4,5,6,7,8])) | |
| 244 self.assertEqual(self.observer.testWarnLists, | |
| 245 [["rpl.rpl_temporary_errors"], | |
| 246 ["main.handler_myisam", "main.ctype_ujis_ucs2", "main.
ctype_recoding"]]) | |
| 247 failtext1 = """rpl.rpl_temporary_errors 'mix' w2 [ fail ] | |
| 248 Test ended at 2009-06-18 16:21:28 | |
| 249 | |
| 250 CURRENT_TEST: rpl.rpl_temporary_errors | |
| 251 Retrying test, attempt(2/3)... | |
| 252 | |
| 253 """ | |
| 254 failtext2 = """main.information_schema_all_engines [ fail ] timeou
t after 900 seconds | |
| 255 Test ended at 2009-06-18 18:37:25 | |
| 256 Retrying test, attempt(2/3)... | |
| 257 | |
| 258 """ | |
| 259 self.assertEqual(self.observer.testFails, | |
| 260 [ ("rpl.rpl_temporary_errors", "mix", "fail", "", failt
ext1), | |
| 261 ("main.information_schema_all_engines", "", "fail", "
timeout after 900 seconds", failtext2) | |
| 262 ]) | |
| 263 self.assertEqual(self.observer.text[1:], ["F:information_s...", "F:rpl_t
emporary...", "W:ctype_recoding", "W:ctype_ujis_ucs2", "W:handler_myisam"]) | |
| 264 | |
| 265 class RemoteShellTest(unittest.TestCase): | |
| 266 def testRepr(self): | |
| 267 # Test for #352 | |
| 268 rsc = buildstep.RemoteShellCommand('.', ('sh', 'make')) | |
| 269 testval = repr(rsc) | |
| 270 rsc = buildstep.RemoteShellCommand('.', ['sh', 'make']) | |
| 271 testval = repr(rsc) | |
| 272 rsc = buildstep.RemoteShellCommand('.', 'make') | |
| 273 testval = repr(rsc) | |
| 274 | |
| 275 | |
| 276 class SubunitLogObserver(subunitlogobserver.SubunitLogObserver): | |
| 277 """Subclassed to allow testing behaviour without a real buildstep.""" | |
| 278 | |
| 279 def __init__(self): | |
| 280 # Skip this test if subunit is not installed. | |
| 281 try: | |
| 282 from subunit import TestProtocolServer | |
| 283 except ImportError: | |
| 284 raise unittest.SkipTest("subunit.TestProtocolServer not available") | |
| 285 subunitlogobserver.SubunitLogObserver.__init__(self) | |
| 286 self.testFails = [] | |
| 287 self.testWarnLists = [] | |
| 288 # We don't have a buildstep in self.step. | |
| 289 # So we'll just install ourself there, so we can check the call of | |
| 290 # setProgress(). | |
| 291 # Same for self.step.step_status.setText() | |
| 292 self.step = self | |
| 293 self.step_status = self | |
| 294 self.progresses = [] | |
| 295 self.text = [] | |
| 296 | |
| 297 def setProgress(self, type, value): | |
| 298 self.progresses.append((type, value)) | |
| 299 | |
| 300 def setText(self, text): | |
| 301 self.text = text | |
| 302 | |
| 303 | |
| 304 class SubunitLogObserverTests(ObserverTestCase): | |
| 305 observer_cls = SubunitLogObserver | |
| 306 | |
| 307 def test1(self): | |
| 308 self._logStdout(""" | |
| 309 test: foo | |
| 310 success: foo | |
| 311 test: bar | |
| 312 failure: bar [ | |
| 313 string | |
| 314 ] | |
| 315 test: gam | |
| 316 skip: gam | |
| 317 test: quux | |
| 318 xfail: quux | |
| 319 """) | |
| 320 self.assertEqual(self.observer.progresses, | |
| 321 [('tests', 1), ('tests', 2), ('tests failed', 1), ('tests', 3), | |
| 322 ('tests failed', 2), ('tests', 4)]) | |
| OLD | NEW |