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 |