blob: 8f63edd894182566b79712d16b3863b65ea5ff90 [file] [log] [blame]
#!/usr/bin/python
# Copyright (C) 2010 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Unit tests for printing.py."""
import optparse
import unittest
import logging
from webkitpy.common import array_stream
from webkitpy.common.system import logtesting
from webkitpy.layout_tests import port
from webkitpy.layout_tests.layout_package import printing
from webkitpy.layout_tests.layout_package import result_summary
from webkitpy.layout_tests.layout_package import test_expectations
from webkitpy.layout_tests.layout_package import test_failures
from webkitpy.layout_tests.layout_package import test_results
from webkitpy.layout_tests.layout_package import test_runner
def get_options(args):
print_options = printing.print_options()
option_parser = optparse.OptionParser(option_list=print_options)
return option_parser.parse_args(args)
class TestUtilityFunctions(unittest.TestCase):
def test_configure_logging(self):
options, args = get_options([])
stream = array_stream.ArrayStream()
handler = printing._configure_logging(stream, options.verbose)
logging.info("this should be logged")
self.assertFalse(stream.empty())
stream.reset()
logging.debug("this should not be logged")
self.assertTrue(stream.empty())
printing._restore_logging(handler)
stream.reset()
options, args = get_options(['--verbose'])
handler = printing._configure_logging(stream, options.verbose)
logging.debug("this should be logged")
self.assertFalse(stream.empty())
printing._restore_logging(handler)
def test_print_options(self):
options, args = get_options([])
self.assertTrue(options is not None)
def test_parse_print_options(self):
def test_switches(args, expected_switches_str,
verbose=False, child_processes=1,
is_fully_parallel=False):
options, args = get_options(args)
if expected_switches_str:
expected_switches = set(expected_switches_str.split(','))
else:
expected_switches = set()
switches = printing.parse_print_options(options.print_options,
verbose,
child_processes,
is_fully_parallel)
self.assertEqual(expected_switches, switches)
# test that we default to the default set of switches
test_switches([], printing.PRINT_DEFAULT)
# test that verbose defaults to everything
test_switches([], printing.PRINT_EVERYTHING, verbose=True)
# test that --print default does what it's supposed to
test_switches(['--print', 'default'], printing.PRINT_DEFAULT)
# test that --print nothing does what it's supposed to
test_switches(['--print', 'nothing'], None)
# test that --print everything does what it's supposed to
test_switches(['--print', 'everything'], printing.PRINT_EVERYTHING)
# this tests that '--print X' overrides '--verbose'
test_switches(['--print', 'actual'], 'actual', verbose=True)
class Testprinter(unittest.TestCase):
def get_printer(self, args=None, single_threaded=False,
is_fully_parallel=False):
args = args or []
printing_options = printing.print_options()
option_parser = optparse.OptionParser(option_list=printing_options)
options, args = option_parser.parse_args(args)
self._port = port.get('test', options)
nproc = 2
if single_threaded:
nproc = 1
regular_output = array_stream.ArrayStream()
buildbot_output = array_stream.ArrayStream()
printer = printing.Printer(self._port, options, regular_output,
buildbot_output, single_threaded,
is_fully_parallel)
return printer, regular_output, buildbot_output
def get_result(self, test, result_type=test_expectations.PASS, run_time=0):
failures = []
if result_type == test_expectations.TIMEOUT:
failures = [test_failures.FailureTimeout()]
elif result_type == test_expectations.CRASH:
failures = [test_failures.FailureCrash()]
path = self._port._filesystem.join(self._port.layout_tests_dir(), test)
return test_results.TestResult(path, failures=failures, test_run_time=run_time)
def get_result_summary(self, tests, expectations_str):
test_paths = [self._port._filesystem.join(self._port.layout_tests_dir(), test) for
test in tests]
expectations = test_expectations.TestExpectations(
self._port, test_paths, expectations_str,
self._port.test_configuration(),
is_lint_mode=False)
rs = result_summary.ResultSummary(expectations, test_paths)
return test_paths, rs, expectations
def test_help_printer(self):
# Here and below we'll call the "regular" printer err and the
# buildbot printer out; this corresponds to how things run on the
# bots with stderr and stdout.
printer, err, out = self.get_printer()
# This routine should print something to stdout. testing what it is
# is kind of pointless.
printer.help_printing()
self.assertFalse(err.empty())
self.assertTrue(out.empty())
def do_switch_tests(self, method_name, switch, to_buildbot,
message='hello', exp_err=None, exp_bot=None):
def do_helper(method_name, switch, message, exp_err, exp_bot):
printer, err, bot = self.get_printer(['--print', switch])
getattr(printer, method_name)(message)
self.assertEqual(err.get(), exp_err)
self.assertEqual(bot.get(), exp_bot)
if to_buildbot:
if exp_err is None:
exp_err = []
if exp_bot is None:
exp_bot = [message + "\n"]
else:
if exp_err is None:
exp_err = [message + "\n"]
if exp_bot is None:
exp_bot = []
do_helper(method_name, 'nothing', 'hello', [], [])
do_helper(method_name, switch, 'hello', exp_err, exp_bot)
do_helper(method_name, 'everything', 'hello', exp_err, exp_bot)
def test_configure_and_cleanup(self):
# This test verifies that calling cleanup repeatedly and deleting
# the object is safe.
printer, err, out = self.get_printer(['--print', 'everything'])
printer.cleanup()
printer.cleanup()
printer = None
def test_print_actual(self):
# Actual results need to be logged to the buildbot's stream.
self.do_switch_tests('print_actual', 'actual', to_buildbot=True)
def test_print_actual_buildbot(self):
# FIXME: Test that the format of the actual results matches what the
# buildbot is expecting.
pass
def test_print_config(self):
self.do_switch_tests('print_config', 'config', to_buildbot=False)
def test_print_expected(self):
self.do_switch_tests('print_expected', 'expected', to_buildbot=False)
def test_print_timing(self):
self.do_switch_tests('print_timing', 'timing', to_buildbot=False)
def test_print_update(self):
# Note that there shouldn't be a carriage return here; updates()
# are meant to be overwritten.
self.do_switch_tests('print_update', 'updates', to_buildbot=False,
message='hello', exp_err=['hello'])
def test_print_one_line_summary(self):
printer, err, out = self.get_printer(['--print', 'nothing'])
printer.print_one_line_summary(1, 1, 0)
self.assertTrue(err.empty())
printer, err, out = self.get_printer(['--print', 'one-line-summary'])
printer.print_one_line_summary(1, 1, 0)
self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
printer, err, out = self.get_printer(['--print', 'everything'])
printer.print_one_line_summary(1, 1, 0)
self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
err.reset()
printer.print_one_line_summary(2, 1, 1)
self.assertEquals(err.get(),
["1 test ran as expected, 1 didn't:\n", "\n"])
err.reset()
printer.print_one_line_summary(3, 2, 1)
self.assertEquals(err.get(),
["2 tests ran as expected, 1 didn't:\n", "\n"])
err.reset()
printer.print_one_line_summary(3, 2, 0)
self.assertEquals(err.get(),
['\n', "2 tests ran as expected (1 didn't run).\n",
'\n'])
def test_print_test_result(self):
# Note here that we don't use meaningful exp_str and got_str values;
# the actual contents of the string are treated opaquely by
# print_test_result() when tracing, and usually we don't want
# to test what exactly is printed, just that something
# was printed (or that nothing was printed).
#
# FIXME: this is actually some goofy layering; it would be nice
# we could refactor it so that the args weren't redundant. Maybe
# the TestResult should contain what was expected, and the
# strings could be derived from the TestResult?
printer, err, out = self.get_printer(['--print', 'nothing'])
result = self.get_result('passes/image.html')
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertTrue(err.empty())
printer, err, out = self.get_printer(['--print', 'unexpected'])
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
self.assertTrue(err.empty())
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertEquals(err.get(),
[' passes/image.html -> unexpected pass\n'])
printer, err, out = self.get_printer(['--print', 'everything'])
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
self.assertTrue(err.empty())
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertEquals(err.get(),
[' passes/image.html -> unexpected pass\n'])
printer, err, out = self.get_printer(['--print', 'nothing'])
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertTrue(err.empty())
printer, err, out = self.get_printer(['--print',
'trace-unexpected'])
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
self.assertTrue(err.empty())
printer, err, out = self.get_printer(['--print',
'trace-unexpected'])
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertFalse(err.empty())
printer, err, out = self.get_printer(['--print',
'trace-unexpected'])
result = self.get_result("passes/text.html")
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertFalse(err.empty())
err.reset()
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
self.assertFalse(err.empty())
printer, err, out = self.get_printer(['--print', 'trace-everything'])
result = self.get_result('passes/image.html')
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
result = self.get_result('failures/expected/missing_text.html')
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
result = self.get_result('failures/expected/missing_check.html')
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
result = self.get_result('failures/expected/missing_image.html')
printer.print_test_result(result, expected=True, exp_str='',
got_str='')
self.assertFalse(err.empty())
err.reset()
printer.print_test_result(result, expected=False, exp_str='',
got_str='')
def test_print_progress(self):
expectations = ''
# test that we print nothing
printer, err, out = self.get_printer(['--print', 'nothing'])
tests = ['passes/text.html', 'failures/expected/timeout.html',
'failures/expected/crash.html']
paths, rs, exp = self.get_result_summary(tests, expectations)
printer.print_progress(rs, False, paths)
self.assertTrue(out.empty())
self.assertTrue(err.empty())
printer.print_progress(rs, True, paths)
self.assertTrue(out.empty())
self.assertTrue(err.empty())
# test regular functionality
printer, err, out = self.get_printer(['--print',
'one-line-progress'])
printer.print_progress(rs, False, paths)
self.assertTrue(out.empty())
self.assertFalse(err.empty())
err.reset()
out.reset()
printer.print_progress(rs, True, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
def test_print_progress__detailed(self):
tests = ['passes/text.html', 'failures/expected/timeout.html',
'failures/expected/crash.html']
expectations = 'BUGX : failures/expected/timeout.html = TIMEOUT'
# first, test that it is disabled properly
# should still print one-line-progress
printer, err, out = self.get_printer(
['--print', 'detailed-progress'], single_threaded=False)
paths, rs, exp = self.get_result_summary(tests, expectations)
printer.print_progress(rs, False, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
# now test the enabled paths
printer, err, out = self.get_printer(
['--print', 'detailed-progress'], single_threaded=True)
paths, rs, exp = self.get_result_summary(tests, expectations)
printer.print_progress(rs, False, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
err.reset()
out.reset()
printer.print_progress(rs, True, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT), False)
rs.add(self.get_result('failures/expected/timeout.html'), True)
rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH), True)
err.reset()
out.reset()
printer.print_progress(rs, False, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
# We only clear the meter when retrying w/ detailed-progress.
err.reset()
out.reset()
printer.print_progress(rs, True, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
printer, err, out = self.get_printer(
['--print', 'detailed-progress,unexpected'], single_threaded=True)
paths, rs, exp = self.get_result_summary(tests, expectations)
printer.print_progress(rs, False, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
err.reset()
out.reset()
printer.print_progress(rs, True, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT), False)
rs.add(self.get_result('failures/expected/timeout.html'), True)
rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH), True)
err.reset()
out.reset()
printer.print_progress(rs, False, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
# We only clear the meter when retrying w/ detailed-progress.
err.reset()
out.reset()
printer.print_progress(rs, True, paths)
self.assertFalse(err.empty())
self.assertTrue(out.empty())
def test_write_nothing(self):
printer, err, out = self.get_printer(['--print', 'nothing'])
printer.write("foo")
self.assertTrue(err.empty())
def test_write_misc(self):
printer, err, out = self.get_printer(['--print', 'misc'])
printer.write("foo")
self.assertFalse(err.empty())
err.reset()
printer.write("foo", "config")
self.assertTrue(err.empty())
def test_write_everything(self):
printer, err, out = self.get_printer(['--print', 'everything'])
printer.write("foo")
self.assertFalse(err.empty())
err.reset()
printer.write("foo", "config")
self.assertFalse(err.empty())
def test_write_verbose(self):
printer, err, out = self.get_printer(['--verbose'])
printer.write("foo")
self.assertTrue(not err.empty() and "foo" in err.get()[0])
self.assertTrue(out.empty())
def test_print_unexpected_results(self):
# This routine is the only one that prints stuff that the bots
# care about.
#
# FIXME: there's some weird layering going on here. It seems
# like we shouldn't be both using an expectations string and
# having to specify whether or not the result was expected.
# This whole set of tests should probably be rewritten.
#
# FIXME: Plus, the fact that we're having to call into
# run_webkit_tests is clearly a layering inversion.
def get_unexpected_results(expected, passing, flaky):
"""Return an unexpected results summary matching the input description.
There are a lot of different combinations of test results that
can be tested; this routine produces various combinations based
on the values of the input flags.
Args
expected: whether the tests ran as expected
passing: whether the tests should all pass
flaky: whether the tests should be flaky (if False, they
produce the same results on both runs; if True, they
all pass on the second run).
"""
paths, rs, exp = self.get_result_summary(tests, expectations)
if expected:
rs.add(self.get_result('passes/text.html', test_expectations.PASS),
expected)
rs.add(self.get_result('failures/expected/timeout.html',
test_expectations.TIMEOUT), expected)
rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH),
expected)
elif passing:
rs.add(self.get_result('passes/text.html'), expected)
rs.add(self.get_result('failures/expected/timeout.html'), expected)
rs.add(self.get_result('failures/expected/crash.html'), expected)
else:
rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT),
expected)
rs.add(self.get_result('failures/expected/timeout.html',
test_expectations.CRASH), expected)
rs.add(self.get_result('failures/expected/crash.html',
test_expectations.TIMEOUT),
expected)
retry = rs
if flaky:
paths, retry, exp = self.get_result_summary(tests,
expectations)
retry.add(self.get_result('passes/text.html'), True)
retry.add(self.get_result('failures/expected/timeout.html'), True)
retry.add(self.get_result('failures/expected/crash.html'), True)
unexpected_results = test_runner.summarize_results(self._port, exp, rs, retry, test_timings={}, only_unexpected=True)
return unexpected_results
tests = ['passes/text.html', 'failures/expected/timeout.html',
'failures/expected/crash.html']
expectations = ''
printer, err, out = self.get_printer(['--print', 'nothing'])
ur = get_unexpected_results(expected=False, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertTrue(out.empty())
printer, err, out = self.get_printer(['--print',
'unexpected-results'])
# test everything running as expected
ur = get_unexpected_results(expected=True, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertTrue(out.empty())
# test failures
err.reset()
out.reset()
ur = get_unexpected_results(expected=False, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
# test unexpected flaky results
err.reset()
out.reset()
ur = get_unexpected_results(expected=False, passing=True, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
# test unexpected passes
err.reset()
out.reset()
ur = get_unexpected_results(expected=False, passing=False, flaky=True)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
err.reset()
out.reset()
printer, err, out = self.get_printer(['--print', 'everything'])
ur = get_unexpected_results(expected=False, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
expectations = """
BUGX : failures/expected/crash.html = CRASH
BUGX : failures/expected/timeout.html = TIMEOUT
"""
err.reset()
out.reset()
ur = get_unexpected_results(expected=False, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
err.reset()
out.reset()
ur = get_unexpected_results(expected=False, passing=True, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
# Test handling of --verbose as well.
err.reset()
out.reset()
printer, err, out = self.get_printer(['--verbose'])
ur = get_unexpected_results(expected=False, passing=False, flaky=False)
printer.print_unexpected_results(ur)
self.assertTrue(err.empty())
self.assertFalse(out.empty())
def test_print_unexpected_results_buildbot(self):
# FIXME: Test that print_unexpected_results() produces the printer the
# buildbot is expecting.
pass
if __name__ == '__main__':
unittest.main()