2 # Copyright (C) 2010 Google Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 """Unit tests for printing.py."""
37 from webkitpy.common import array_stream
38 from webkitpy.common.system import logtesting
39 from webkitpy.layout_tests import port
40 from webkitpy.layout_tests.controllers import manager
41 from webkitpy.layout_tests.models import result_summary
42 from webkitpy.layout_tests.models import test_expectations
43 from webkitpy.layout_tests.models import test_failures
44 from webkitpy.layout_tests.models import test_results
45 from webkitpy.layout_tests.views import printing
48 def get_options(args):
49 print_options = printing.print_options()
50 option_parser = optparse.OptionParser(option_list=print_options)
51 return option_parser.parse_args(args)
54 class TestUtilityFunctions(unittest.TestCase):
55 def test_configure_logging(self):
56 options, args = get_options([])
57 stream = array_stream.ArrayStream()
58 handler = printing._configure_logging(stream, options.verbose)
59 logging.info("this should be logged")
60 self.assertFalse(stream.empty())
63 logging.debug("this should not be logged")
64 self.assertTrue(stream.empty())
66 printing._restore_logging(handler)
69 options, args = get_options(['--verbose'])
70 handler = printing._configure_logging(stream, options.verbose)
71 logging.debug("this should be logged")
72 self.assertFalse(stream.empty())
73 printing._restore_logging(handler)
75 def test_print_options(self):
76 options, args = get_options([])
77 self.assertTrue(options is not None)
79 def test_parse_print_options(self):
80 def test_switches(args, expected_switches_str, verbose=False):
81 options, args = get_options(args)
82 if expected_switches_str:
83 expected_switches = set(expected_switches_str.split(','))
85 expected_switches = set()
86 switches = printing.parse_print_options(options.print_options,
88 self.assertEqual(expected_switches, switches)
90 # test that we default to the default set of switches
91 test_switches([], printing.PRINT_DEFAULT)
93 # test that verbose defaults to everything
94 test_switches([], printing.PRINT_EVERYTHING, verbose=True)
96 # test that --print default does what it's supposed to
97 test_switches(['--print', 'default'], printing.PRINT_DEFAULT)
99 # test that --print nothing does what it's supposed to
100 test_switches(['--print', 'nothing'], None)
102 # test that --print everything does what it's supposed to
103 test_switches(['--print', 'everything'], printing.PRINT_EVERYTHING)
105 # this tests that '--print X' overrides '--verbose'
106 test_switches(['--print', 'actual'], 'actual', verbose=True)
110 class Testprinter(unittest.TestCase):
111 def get_printer(self, args=None, tty=False):
113 printing_options = printing.print_options()
114 option_parser = optparse.OptionParser(option_list=printing_options)
115 options, args = option_parser.parse_args(args)
116 self._port = port.get('test', options)
119 regular_output = array_stream.ArrayStream(tty=tty)
120 buildbot_output = array_stream.ArrayStream()
121 printer = printing.Printer(self._port, options, regular_output,
122 buildbot_output, configure_logging=True)
123 return printer, regular_output, buildbot_output
125 def get_result(self, test_name, result_type=test_expectations.PASS, run_time=0):
127 if result_type == test_expectations.TIMEOUT:
128 failures = [test_failures.FailureTimeout()]
129 elif result_type == test_expectations.CRASH:
130 failures = [test_failures.FailureCrash()]
131 return test_results.TestResult(test_name, failures=failures, test_run_time=run_time)
133 def get_result_summary(self, test_names, expectations_str):
134 expectations = test_expectations.TestExpectations(
135 self._port, test_names, expectations_str,
136 self._port.test_configuration(),
139 rs = result_summary.ResultSummary(expectations, test_names)
140 return test_names, rs, expectations
142 def test_help_printer(self):
143 # Here and below we'll call the "regular" printer err and the
144 # buildbot printer out; this corresponds to how things run on the
145 # bots with stderr and stdout.
146 printer, err, out = self.get_printer()
148 # This routine should print something to stdout. testing what it is
149 # is kind of pointless.
150 printer.help_printing()
151 self.assertFalse(err.empty())
152 self.assertTrue(out.empty())
154 def do_switch_tests(self, method_name, switch, to_buildbot,
155 message='hello', exp_err=None, exp_bot=None):
156 def do_helper(method_name, switch, message, exp_err, exp_bot):
157 printer, err, bot = self.get_printer(['--print', switch], tty=True)
158 getattr(printer, method_name)(message)
159 self.assertEqual(err.get(), exp_err)
160 self.assertEqual(bot.get(), exp_bot)
166 exp_bot = [message + "\n"]
169 exp_err = [message + "\n"]
172 do_helper(method_name, 'nothing', 'hello', [], [])
173 do_helper(method_name, switch, 'hello', exp_err, exp_bot)
174 do_helper(method_name, 'everything', 'hello', exp_err, exp_bot)
176 def test_configure_and_cleanup(self):
177 # This test verifies that calling cleanup repeatedly and deleting
178 # the object is safe.
179 printer, err, out = self.get_printer(['--print', 'everything'])
184 def test_print_actual(self):
185 # Actual results need to be logged to the buildbot's stream.
186 self.do_switch_tests('print_actual', 'actual', to_buildbot=True)
188 def test_print_actual_buildbot(self):
189 # FIXME: Test that the format of the actual results matches what the
190 # buildbot is expecting.
193 def test_print_config(self):
194 self.do_switch_tests('print_config', 'config', to_buildbot=False)
196 def test_print_expected(self):
197 self.do_switch_tests('print_expected', 'expected', to_buildbot=False)
199 def test_print_timing(self):
200 self.do_switch_tests('print_timing', 'timing', to_buildbot=False)
202 def test_print_update(self):
203 # Note that there shouldn't be a carriage return here; updates()
204 # are meant to be overwritten.
205 self.do_switch_tests('print_update', 'updates', to_buildbot=False,
206 message='hello', exp_err=['hello'])
208 def test_print_one_line_summary(self):
209 printer, err, out = self.get_printer(['--print', 'nothing'])
210 printer.print_one_line_summary(1, 1, 0)
211 self.assertTrue(err.empty())
213 printer, err, out = self.get_printer(['--print', 'one-line-summary'])
214 printer.print_one_line_summary(1, 1, 0)
215 self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
217 printer, err, out = self.get_printer(['--print', 'everything'])
218 printer.print_one_line_summary(1, 1, 0)
219 self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
222 printer.print_one_line_summary(2, 1, 1)
223 self.assertEquals(err.get(),
224 ["1 test ran as expected, 1 didn't:\n", "\n"])
227 printer.print_one_line_summary(3, 2, 1)
228 self.assertEquals(err.get(),
229 ["2 tests ran as expected, 1 didn't:\n", "\n"])
232 printer.print_one_line_summary(3, 2, 0)
233 self.assertEquals(err.get(),
234 ['\n', "2 tests ran as expected (1 didn't run).\n",
238 def test_print_test_result(self):
239 # Note here that we don't use meaningful exp_str and got_str values;
240 # the actual contents of the string are treated opaquely by
241 # print_test_result() when tracing, and usually we don't want
242 # to test what exactly is printed, just that something
243 # was printed (or that nothing was printed).
245 # FIXME: this is actually some goofy layering; it would be nice
246 # we could refactor it so that the args weren't redundant. Maybe
247 # the TestResult should contain what was expected, and the
248 # strings could be derived from the TestResult?
249 printer, err, out = self.get_printer(['--print', 'nothing'])
250 result = self.get_result('passes/image.html')
251 printer.print_test_result(result, expected=False, exp_str='',
253 self.assertTrue(err.empty())
255 printer, err, out = self.get_printer(['--print', 'unexpected'])
256 printer.print_test_result(result, expected=True, exp_str='',
258 self.assertTrue(err.empty())
259 printer.print_test_result(result, expected=False, exp_str='',
261 self.assertEquals(err.get(),
262 [' passes/image.html -> unexpected pass\n'])
264 printer, err, out = self.get_printer(['--print', 'everything'])
265 printer.print_test_result(result, expected=True, exp_str='',
267 self.assertTrue(err.empty())
269 printer.print_test_result(result, expected=False, exp_str='',
271 self.assertEquals(err.get(),
272 [' passes/image.html -> unexpected pass\n'])
274 printer, err, out = self.get_printer(['--print', 'nothing'])
275 printer.print_test_result(result, expected=False, exp_str='',
277 self.assertTrue(err.empty())
279 printer, err, out = self.get_printer(['--print',
281 printer.print_test_result(result, expected=True, exp_str='',
283 self.assertTrue(err.empty())
285 printer, err, out = self.get_printer(['--print',
287 printer.print_test_result(result, expected=False, exp_str='',
289 self.assertFalse(err.empty())
291 printer, err, out = self.get_printer(['--print',
293 result = self.get_result("passes/text.html")
294 printer.print_test_result(result, expected=False, exp_str='',
296 self.assertFalse(err.empty())
299 printer.print_test_result(result, expected=False, exp_str='',
301 self.assertFalse(err.empty())
303 printer, err, out = self.get_printer(['--print', 'trace-everything'])
304 result = self.get_result('passes/image.html')
305 printer.print_test_result(result, expected=True, exp_str='',
307 result = self.get_result('failures/expected/missing_text.html')
308 printer.print_test_result(result, expected=True, exp_str='',
310 result = self.get_result('failures/expected/missing_check.html')
311 printer.print_test_result(result, expected=True, exp_str='',
313 result = self.get_result('failures/expected/missing_image.html')
314 printer.print_test_result(result, expected=True, exp_str='',
316 self.assertFalse(err.empty())
319 printer.print_test_result(result, expected=False, exp_str='',
322 def test_print_progress(self):
325 printer, err, out = self.get_printer(['--print', 'nothing'])
326 tests = ['passes/text.html', 'failures/expected/timeout.html',
327 'failures/expected/crash.html']
328 paths, rs, exp = self.get_result_summary(tests, expectations)
330 # First, test that we print nothing.
331 printer.print_progress(rs, False, paths)
332 self.assertTrue(out.empty())
333 self.assertTrue(err.empty())
335 printer.print_progress(rs, True, paths)
336 self.assertTrue(out.empty())
337 self.assertTrue(err.empty())
339 self.times = [1, 2, 12, 13, 14, 23, 33]
342 return self.times.pop(0)
344 orig_time = time.time
346 time.time = mock_time
348 # Test printing progress updates to a file.
349 printer, err, out = self.get_printer(['--print', 'one-line-progress'])
350 printer.print_progress(rs, False, paths)
351 printer.print_progress(rs, False, paths)
352 self.assertTrue(out.empty())
353 self.assertTrue(err.empty())
355 printer.print_progress(rs, False, paths)
356 self.assertTrue(out.empty())
357 self.assertFalse(err.empty())
361 printer.print_progress(rs, True, paths)
362 self.assertTrue(out.empty())
363 self.assertTrue(err.empty())
365 printer.print_progress(rs, True, paths)
366 self.assertTrue(out.empty())
367 self.assertFalse(err.empty())
369 # Now reconfigure the printer to test printing to a TTY instead of a file.
370 self.times = [1, 1.01, 2, 3]
371 printer, err, out = self.get_printer(['--print', 'one-line-progress'], tty=True)
372 printer.print_progress(rs, False, paths)
373 printer.print_progress(rs, False, paths)
374 self.assertTrue(out.empty())
375 self.assertTrue(err.empty())
377 printer.print_progress(rs, False, paths)
378 self.assertTrue(out.empty())
379 self.assertFalse(err.empty())
383 printer.print_progress(rs, True, paths)
384 self.assertTrue(out.empty())
385 self.assertFalse(err.empty())
387 time.time = orig_time
389 def test_write_nothing(self):
390 printer, err, out = self.get_printer(['--print', 'nothing'])
392 self.assertTrue(err.empty())
394 def test_write_misc(self):
395 printer, err, out = self.get_printer(['--print', 'misc'])
397 self.assertFalse(err.empty())
399 printer.write("foo", "config")
400 self.assertTrue(err.empty())
402 def test_write_everything(self):
403 printer, err, out = self.get_printer(['--print', 'everything'])
405 self.assertFalse(err.empty())
407 printer.write("foo", "config")
408 self.assertFalse(err.empty())
410 def test_write_verbose(self):
411 printer, err, out = self.get_printer(['--verbose'])
413 self.assertTrue(not err.empty() and "foo" in err.get()[0])
414 self.assertTrue(out.empty())
416 def test_print_unexpected_results(self):
417 # This routine is the only one that prints stuff that the bots
420 # FIXME: there's some weird layering going on here. It seems
421 # like we shouldn't be both using an expectations string and
422 # having to specify whether or not the result was expected.
423 # This whole set of tests should probably be rewritten.
425 # FIXME: Plus, the fact that we're having to call into
426 # run_webkit_tests is clearly a layering inversion.
427 def get_unexpected_results(expected, passing, flaky):
428 """Return an unexpected results summary matching the input description.
430 There are a lot of different combinations of test results that
431 can be tested; this routine produces various combinations based
432 on the values of the input flags.
435 expected: whether the tests ran as expected
436 passing: whether the tests should all pass
437 flaky: whether the tests should be flaky (if False, they
438 produce the same results on both runs; if True, they
439 all pass on the second run).
442 paths, rs, exp = self.get_result_summary(tests, expectations)
444 rs.add(self.get_result('passes/text.html', test_expectations.PASS), expected)
445 rs.add(self.get_result('failures/expected/timeout.html', test_expectations.TIMEOUT), expected)
446 rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH), expected)
448 rs.add(self.get_result('passes/text.html'), expected)
449 rs.add(self.get_result('failures/expected/timeout.html'), expected)
450 rs.add(self.get_result('failures/expected/crash.html'), expected)
452 rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT), expected)
453 rs.add(self.get_result('failures/expected/timeout.html', test_expectations.CRASH), expected)
454 rs.add(self.get_result('failures/expected/crash.html', test_expectations.TIMEOUT), expected)
457 paths, retry, exp = self.get_result_summary(tests, expectations)
458 retry.add(self.get_result('passes/text.html'), True)
459 retry.add(self.get_result('failures/expected/timeout.html'), True)
460 retry.add(self.get_result('failures/expected/crash.html'), True)
461 unexpected_results = manager.summarize_results(self._port, exp, rs, retry, test_timings={}, only_unexpected=True, interrupted=False)
462 return unexpected_results
464 tests = ['passes/text.html', 'failures/expected/timeout.html', 'failures/expected/crash.html']
467 printer, err, out = self.get_printer(['--print', 'nothing'])
468 ur = get_unexpected_results(expected=False, passing=False, flaky=False)
469 printer.print_unexpected_results(ur)
470 self.assertTrue(err.empty())
471 self.assertTrue(out.empty())
473 printer, err, out = self.get_printer(['--print', 'unexpected-results'])
475 # test everything running as expected
476 ur = get_unexpected_results(expected=True, passing=False, flaky=False)
477 printer.print_unexpected_results(ur)
478 self.assertTrue(err.empty())
479 self.assertTrue(out.empty())
484 ur = get_unexpected_results(expected=False, passing=False, flaky=False)
485 printer.print_unexpected_results(ur)
486 self.assertTrue(err.empty())
487 self.assertFalse(out.empty())
489 # test unexpected flaky
492 ur = get_unexpected_results(expected=False, passing=False, flaky=True)
493 printer.print_unexpected_results(ur)
494 self.assertTrue(err.empty())
495 self.assertFalse(out.empty())
499 printer, err, out = self.get_printer(['--print', 'everything'])
500 ur = get_unexpected_results(expected=False, passing=False, flaky=False)
501 printer.print_unexpected_results(ur)
502 self.assertTrue(err.empty())
503 self.assertFalse(out.empty())
506 BUGX : failures/expected/crash.html = CRASH
507 BUGX : failures/expected/timeout.html = TIMEOUT
511 ur = get_unexpected_results(expected=False, passing=False, flaky=False)
512 printer.print_unexpected_results(ur)
513 self.assertTrue(err.empty())
514 self.assertFalse(out.empty())
518 ur = get_unexpected_results(expected=False, passing=True, flaky=False)
519 printer.print_unexpected_results(ur)
520 self.assertTrue(err.empty())
521 self.assertFalse(out.empty())
523 # Test handling of --verbose as well.
526 printer, err, out = self.get_printer(['--verbose'])
527 ur = get_unexpected_results(expected=False, passing=False, flaky=False)
528 printer.print_unexpected_results(ur)
529 # FIXME: debug output from the port and scm objects may or may not go
530 # to stderr, so there's no point in testing its contents here.
531 self.assertFalse(out.empty())
533 def test_print_unexpected_results_buildbot(self):
534 # FIXME: Test that print_unexpected_results() produces the printer the
535 # buildbot is expecting.
538 if __name__ == '__main__':