diff options
author | Iain Merrick <husky@google.com> | 2010-09-13 16:35:48 +0100 |
---|---|---|
committer | Iain Merrick <husky@google.com> | 2010-09-16 12:10:42 +0100 |
commit | 5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306 (patch) | |
tree | ddce1aa5e3b6967a69691892e500897558ff8ab6 /WebKitTools/Scripts/webkitpy/layout_tests/layout_package | |
parent | 12bec63ec71e46baba27f0bd9bd9d8067683690a (diff) | |
download | external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.zip external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.tar.gz external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.tar.bz2 |
Merge WebKit at r67178 : Initial merge by git.
Change-Id: I57e01163b6866cb029cdadf405a0394a3918bc18
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/layout_tests/layout_package')
3 files changed, 125 insertions, 16 deletions
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index ec33086..9b963ca 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -47,6 +47,7 @@ import sys import thread import threading import time +import traceback import test_failures @@ -54,6 +55,23 @@ _log = logging.getLogger("webkitpy.layout_tests.layout_package." "dump_render_tree_thread") +def find_thread_stack(id): + """Returns a stack object that can be used to dump a stack trace for + the given thread id (or None if the id is not found).""" + for thread_id, stack in sys._current_frames().items(): + if thread_id == id: + return stack + return None + + +def log_stack(stack): + """Log a stack trace to log.error().""" + for filename, lineno, name, line in traceback.extract_stack(stack): + _log.error('File: "%s", line %d, in %s' % (filename, lineno, name)) + if line: + _log.error(' %s' % line.strip()) + + def _process_output(port, test_info, test_types, test_args, configuration, output_dir, crash, timeout, test_run_time, actual_checksum, output, error): @@ -167,6 +185,7 @@ class SingleTestThread(threading.Thread): self._test_args = test_args self._configuration = configuration self._output_dir = output_dir + self._driver = None def run(self): self._covered_run() @@ -175,18 +194,19 @@ class SingleTestThread(threading.Thread): # FIXME: this is a separate routine to work around a bug # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85. test_info = self._test_info - driver = self._port.create_driver(self._image_path, self._shell_args) - driver.start() + self._driver = self._port.create_driver(self._image_path, + self._shell_args) + self._driver.start() start = time.time() crash, timeout, actual_checksum, output, error = \ - driver.run_test(test_info.uri.strip(), test_info.timeout, - test_info.image_hash()) + self._driver.run_test(test_info.uri.strip(), test_info.timeout, + test_info.image_hash()) end = time.time() self._test_result = _process_output(self._port, test_info, self._test_types, self._test_args, self._configuration, self._output_dir, crash, timeout, end - start, actual_checksum, output, error) - driver.stop() + self._driver.stop() def get_test_result(self): return self._test_result @@ -312,9 +332,7 @@ class TestShellThread(WatchableThread): # Save the exception for our caller to see. self._exception_info = sys.exc_info() self._stop_time = time.time() - # Re-raise it and die. - _log.error('%s dying, exception raised: %s' % (self.getName(), - self._exception_info)) + _log.error('%s dying, exception raised' % self.getName()) self._stop_time = time.time() @@ -426,7 +444,7 @@ class TestShellThread(WatchableThread): worker.start() thread_timeout = _milliseconds_to_seconds( - _pad_timeout(test_info.timeout)) + _pad_timeout(int(test_info.timeout))) thread._next_timeout = time.time() + thread_timeout worker.join(thread_timeout) if worker.isAlive(): @@ -439,11 +457,13 @@ class TestShellThread(WatchableThread): # that tradeoff in order to avoid losing the rest of this # thread's results. _log.error('Test thread hung: killing all DumpRenderTrees') - worker._driver.stop() + if worker._driver: + worker._driver.stop() try: result = worker.get_test_result() except AttributeError, e: + # This gets raised if the worker thread has already exited. failures = [] _log.error('Cannot get results of test: %s' % test_info.filename) @@ -476,7 +496,7 @@ class TestShellThread(WatchableThread): start = time.time() thread_timeout = _milliseconds_to_seconds( - _pad_timeout(test_info.timeout)) + _pad_timeout(int(test_info.timeout))) self._next_timeout = start + thread_timeout crash, timeout, actual_checksum, output, error = \ diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py new file mode 100644 index 0000000..63f86d9 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py @@ -0,0 +1,49 @@ +# 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. + +""""Tests code paths not covered by the regular unit tests.""" + +import sys +import unittest + +import dump_render_tree_thread + + +class Test(unittest.TestCase): + def test_find_thread_stack_found(self): + id, stack = sys._current_frames().items()[0] + found_stack = dump_render_tree_thread.find_thread_stack(id) + self.assertNotEqual(found_stack, None) + + def test_find_thread_stack_not_found(self): + found_stack = dump_render_tree_thread.find_thread_stack(0) + self.assertEqual(found_stack, None) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py index 15eceee..765b4d8 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py @@ -37,6 +37,8 @@ import time import urllib2 import xml.dom.minidom +from webkitpy.layout_tests.layout_package import test_results_uploader + import webkitpy.thirdparty.simplejson as simplejson # A JSON results generator for generic tests. @@ -85,13 +87,14 @@ class JSONResultsGeneratorBase(object): INCREMENTAL_RESULTS_FILENAME = "incremental_results.json" URL_FOR_TEST_LIST_JSON = \ - "http://%s/testfile?builder=%s&name=%s&testlistjson=1" + "http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s" def __init__(self, builder_name, build_name, build_number, results_file_base_path, builder_base_url, test_results_map, svn_repositories=None, generate_incremental_results=False, - test_results_server=None): + test_results_server=None, + test_type=""): """Modifies the results.json file. Grabs it off the archive directory if it is not found locally. @@ -129,6 +132,7 @@ class JSONResultsGeneratorBase(object): self._svn_repositories = {} self._test_results_server = test_results_server + self._test_type = test_type self._json = None self._archived_results = None @@ -287,7 +291,8 @@ class JSONResultsGeneratorBase(object): results_file_url = (self.URL_FOR_TEST_LIST_JSON % (urllib2.quote(self._test_results_server), urllib2.quote(self._builder_name), - self.RESULTS_FILENAME)) + self.RESULTS_FILENAME, + urllib2.quote(self._test_type))) else: # Check if we have the archived JSON file on the buildbot # server. @@ -518,9 +523,33 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): # The flag is for backward compatibility. output_json_in_init = True + def _upload_json_files(self): + if not self._test_results_server or not self._test_type: + return + + _log.info("Uploading JSON files for %s to the server: %s", + self._builder_name, self._test_results_server) + attrs = [("builder", self._builder_name), ("testtype", self._test_type)] + json_files = [self.INCREMENTAL_RESULTS_FILENAME] + + files = [(file, os.path.join(self._results_directory, file)) + for file in json_files] + uploader = test_results_uploader.TestResultsUploader( + self._test_results_server) + try: + # Set uploading timeout in case appengine server is having problem. + # 120 seconds are more than enough to upload test results. + uploader.upload(attrs, files, 120) + except Exception, err: + _log.error("Upload failed: %s" % err) + return + + _log.info("JSON files uploaded.") + def __init__(self, port, builder_name, build_name, build_number, results_file_base_path, builder_base_url, - test_timings, failures, passed_tests, skipped_tests, all_tests): + test_timings, failures, passed_tests, skipped_tests, all_tests, + test_results_server=None, test_type=None): """Generates a JSON results file. Args @@ -536,8 +565,13 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): skipped_tests: A set containing all the skipped tests. all_tests: List of all the tests that were run. This should not include skipped tests. + test_results_server: server that hosts test results json. + test_type: the test type. """ + self._test_type = test_type + self._results_directory = results_file_base_path + # Create a map of (name, TestResult). test_results_map = dict() get = test_results_map.get @@ -557,10 +591,16 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): if test not in test_results_map: test_results_map[test] = TestResult(test) + # Generate the JSON with incremental flag enabled. + # (This should also output the full result for now.) super(JSONResultsGenerator, self).__init__( builder_name, build_name, build_number, results_file_base_path, builder_base_url, test_results_map, - svn_repositories=port.test_repository_paths()) + svn_repositories=port.test_repository_paths(), + generate_incremental_results=True, + test_results_server=test_results_server, + test_type=test_type) if self.__class__.output_json_in_init: self.generate_json_output() + self._upload_json_files() |