blob: fbcd2fd7c4689ab004a4172fee37b3670dbdfa13 [file] [log] [blame]
# Copyright (C) 2017 Igalia S.L.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
import json
import logging
import os
from webkitpy.common.webkit_finder import WebKitFinder
from webkitpy.common.test_expectations import TestExpectations
from webkitpy.webdriver_tests.webdriver_driver import create_driver
from webkitpy.webdriver_tests.webdriver_test_runner_selenium import WebDriverTestRunnerSelenium
from webkitpy.webdriver_tests.webdriver_test_runner_w3c import WebDriverTestRunnerW3C
_log = logging.getLogger(__name__)
class WebDriverTestRunner(object):
RUNNER_CLASSES = (WebDriverTestRunnerSelenium, WebDriverTestRunnerW3C)
def __init__(self, port):
self._port = port
_log.info('Using port %s' % self._port.name())
_log.info('Test configuration: %s' % self._port.test_configuration())
_log.info('Using display server %s' % (self._port._display_server))
self._display_driver = self._port._driver_class()(self._port, worker_number=0, pixel_tests=False, no_timeout=True)
if not self._display_driver.check_driver(self._port):
raise RuntimeError("Failed to check driver %s" % self._display_driver.__class__.__name__)
driver = create_driver(self._port)
_log.info('Using driver at %s' % (driver.binary_path()))
_log.info('Browser: %s' % (driver.browser_name()))
_log.info('Parsing expectations')
self._tests_dir = WebKitFinder(self._port.host.filesystem).path_from_webkit_base('WebDriverTests')
expectations_file = os.path.join(self._tests_dir, 'TestExpectations.json')
build_type = 'Debug' if self._port.get_option('debug') else 'Release'
self._expectations = TestExpectations(self._port.name(), expectations_file, build_type)
for test in self._expectations._expectations.keys():
if not os.path.isfile(os.path.join(self._tests_dir, test)):
_log.warning('Test %s does not exist' % test)
env = self._display_driver._setup_environ_for_test()
self._runners = [runner_cls(self._port, driver, env, self._expectations) for runner_cls in self.RUNNER_CLASSES]
def teardown(self):
self._display_driver.stop()
def run(self, tests=[]):
runner_tests = [runner.collect_tests(tests) for runner in self._runners]
collected_count = sum([len(tests) for tests in runner_tests])
if not collected_count:
_log.info('No tests found')
return 0
_log.info('Collected %d test files' % collected_count)
for i in range(len(self._runners)):
if runner_tests[i]:
self._runners[i].run(runner_tests[i])
def process_results(self):
results = {}
expected_count = 0
passed_count = 0
failures_count = 0
timeout_count = 0
test_results = []
for runner in self._runners:
test_results.extend(runner.results())
for result in test_results:
if result.status == 'OK':
for subtest, status, _, _ in result.subtest_results:
if status in ['PASS', 'SKIP', 'XFAIL']:
expected_count += 1
elif status in ['FAIL', 'ERROR']:
results.setdefault('FAIL', []).append(os.path.join(os.path.dirname(result.test), subtest))
failures_count += 1
elif status == 'TIMEOUT':
results.setdefault('TIMEOUT', []).append(os.path.join(os.path.dirname(result.test), subtest))
timeout_count += 1
elif status in ['XPASS', 'XPASS_TIMEOUT']:
results.setdefault(status, []).append(os.path.join(os.path.dirname(result.test), subtest))
passed_count += 1
elif result.status == 'ERROR': # Harness execution error
results.setdefault('FAIL', []).append(result.test)
else:
# FIXME: handle other results.
pass
_log.info('')
retval = 0
if not results:
_log.info('All tests run as expected')
return retval
_log.info('%d tests ran as expected, %d didn\'t\n' % (expected_count, failures_count + timeout_count + passed_count))
def report(status, actual, expected=None):
retval = 0
if status not in results:
return retval
tests = results[status]
tests_count = len(tests)
if expected is None:
_log.info('Unexpected %s (%d)' % (actual, tests_count))
retval += tests_count
else:
_log.info('Expected to %s, but %s (%d)' % (expected, actual, tests_count))
for test in tests:
_log.info(' %s' % test)
_log.info('')
return retval
report('XPASS', 'passed', 'fail')
report('XPASS_TIMEOUT', 'passed', 'timeout')
retval += report('FAIL', 'failures')
retval += report('TIMEOUT', 'timeouts')
return retval
def dump_results_to_json_file(self, output_path):
json_results = {}
json_results['results'] = []
test_results = []
for runner in self._runners:
test_results.extend(runner.results())
for result in test_results:
results = {}
results['test'] = result.test
results['status'] = result.status
results['message'] = result.message
results['subtests'] = []
for name, status, message, _ in result.subtest_results:
subtest = {}
subtest['name'] = name.split('::', 1)[1]
subtest['status'] = status
subtest['message'] = message
results['subtests'].append(subtest)
json_results['results'].append(results)
directory = os.path.dirname(output_path)
if directory and not os.path.exists(directory):
os.makedirs(directory)
with open(output_path, 'w') as fp:
json.dump(json_results, fp)