Changeset 84595 in webkit


Ignore:
Timestamp:
Apr 21, 2011 8:28:23 PM (13 years ago)
Author:
dpranke@chromium.org
Message:

2011-04-21 Dirk Pranke <dpranke@chromium.org>

Reviewed by Tony Chang.

new-run-webkit-tests: obsolete old code, part 4: merge worker_mixin into worker
https://bugs.webkit.org/show_bug.cgi?id=58756

Since worker_mixin is now only used by worker, there's no point
in having it split across two files.

  • Scripts/webkitpy/layout_tests/layout_package/worker.py:
  • Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py: Removed.
Location:
trunk/Tools
Files:
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r84594 r84595  
     12011-04-21  Dirk Pranke  <dpranke@chromium.org>
     2
     3        Reviewed by Tony Chang.
     4
     5        new-run-webkit-tests: obsolete old code, part 4: merge worker_mixin into worker
     6        https://bugs.webkit.org/show_bug.cgi?id=58756
     7
     8        Since worker_mixin is now only used by worker, there's no point
     9        in having it split across two files.
     10
     11        * Scripts/webkitpy/layout_tests/layout_package/worker.py:
     12        * Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py: Removed.
     13
    1142011-04-21  Dirk Pranke  <dpranke@chromium.org>
    215
  • trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py

    r84467 r84595  
    2727# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2828
    29 """Handle messages from the TestRunner and execute actual tests."""
     29"""Handle messages from the Manager and executes actual tests."""
    3030
    3131import logging
    3232import sys
     33import threading
    3334import time
    3435
    3536from webkitpy.common.system import stack_utils
    36 
    3737from webkitpy.layout_tests.layout_package import manager_worker_broker
    38 from webkitpy.layout_tests.layout_package import worker_mixin
    39 
     38from webkitpy.layout_tests.layout_package import single_test_runner
     39from webkitpy.layout_tests.layout_package import test_results
    4040
    4141_log = logging.getLogger(__name__)
    4242
    4343
    44 class Worker(manager_worker_broker.AbstractWorker, worker_mixin.WorkerMixin):
     44class Worker(manager_worker_broker.AbstractWorker):
    4545    def __init__(self, worker_connection, worker_number, options):
    4646        self._worker_connection = worker_connection
     
    5454    def __del__(self):
    5555        self.cleanup()
     56
     57    def safe_init(self, port):
     58        """This method should only be called when it is is safe for the mixin
     59        to create state that can't be Pickled.
     60
     61        This routine exists so that the mixin can be created and then marshaled
     62        across into a child process."""
     63        self._port = port
     64        self._filesystem = port._filesystem
     65        self._batch_count = 0
     66        self._batch_size = self._options.batch_size
     67        self._driver = None
     68        tests_run_filename = self._filesystem.join(port.results_directory(),
     69                                                   "tests_run%d.txt" % self._worker_number)
     70        self._tests_run_file = self._filesystem.open_text_file_for_writing(tests_run_filename)
     71
     72        # FIXME: it's goofy that we have to track this at all, but it's due to
     73        # the awkward logic in TestShellThread._run(). When we remove that
     74        # file, we should rewrite this code so that caller keeps track of whether
     75        # the lock is held.
     76        self._has_http_lock = False
    5677
    5778    def cancel(self):
     
    121142
    122143        self.clean_up_after_test(test_input, result)
     144
     145    def cleanup(self):
     146        if self._driver:
     147            self.kill_driver()
     148        if self._has_http_lock:
     149            self.stop_servers_with_lock()
     150        if self._tests_run_file:
     151            self._tests_run_file.close()
     152            self._tests_run_file = None
     153
     154    def timeout(self, test_input):
     155        """Compute the appropriate timeout value for a test."""
     156        # The DumpRenderTree watchdog uses 2.5x the timeout; we want to be
     157        # larger than that. We also add a little more padding if we're
     158        # running tests in a separate thread.
     159        #
     160        # Note that we need to convert the test timeout from a
     161        # string value in milliseconds to a float for Python.
     162        driver_timeout_sec = 3.0 * float(test_input.timeout) / 1000.0
     163        if not self._options.run_singly:
     164            return driver_timeout_sec
     165
     166        thread_padding_sec = 1.0
     167        thread_timeout_sec = driver_timeout_sec + thread_padding_sec
     168        return thread_timeout_sec
     169
     170    def start_servers_with_lock(self):
     171        _log.debug('Acquiring http lock ...')
     172        self._port.acquire_http_lock()
     173        _log.debug('Starting HTTP server ...')
     174        self._port.start_http_server()
     175        _log.debug('Starting WebSocket server ...')
     176        self._port.start_websocket_server()
     177        self._has_http_lock = True
     178
     179    def stop_servers_with_lock(self):
     180        if self._has_http_lock:
     181            _log.debug('Stopping HTTP server ...')
     182            self._port.stop_http_server()
     183            _log.debug('Stopping WebSocket server ...')
     184            self._port.stop_websocket_server()
     185            _log.debug('Releasing server lock ...')
     186            self._port.release_http_lock()
     187            self._has_http_lock = False
     188
     189    def kill_driver(self):
     190        if self._driver:
     191            self._driver.stop()
     192            self._driver = None
     193
     194    def run_test_with_timeout(self, test_input, timeout):
     195        if self._options.run_singly:
     196            return self._run_test_in_another_thread(test_input, timeout)
     197        else:
     198            return self._run_test_in_this_thread(test_input)
     199        return result
     200
     201    def clean_up_after_test(self, test_input, result):
     202        self._batch_count += 1
     203        self._tests_run_file.write(test_input.filename + "\n")
     204        test_name = self._port.relative_test_filename(test_input.filename)
     205
     206        if result.failures:
     207            # Check and kill DumpRenderTree if we need to.
     208            if any([f.should_kill_dump_render_tree() for f in result.failures]):
     209                self.kill_driver()
     210                # Reset the batch count since the shell just bounced.
     211                self._batch_count = 0
     212
     213            # Print the error message(s).
     214            _log.debug("%s %s failed:" % (self._name, test_name))
     215            for f in result.failures:
     216                _log.debug("%s  %s" % (self._name, f.message()))
     217        else:
     218            _log.debug("%s %s passed" % (self._name, test_name))
     219
     220        if self._batch_size > 0 and self._batch_count >= self._batch_size:
     221            # Bounce the shell and reset count.
     222            self.kill_driver()
     223            self._batch_count = 0
     224
     225    def _run_test_in_another_thread(self, test_input, thread_timeout_sec):
     226        """Run a test in a separate thread, enforcing a hard time limit.
     227
     228        Since we can only detect the termination of a thread, not any internal
     229        state or progress, we can only run per-test timeouts when running test
     230        files singly.
     231
     232        Args:
     233          test_input: Object containing the test filename and timeout
     234          thread_timeout_sec: time to wait before killing the driver process.
     235        Returns:
     236          A TestResult
     237        """
     238        worker = self
     239
     240        driver = worker._port.create_driver(worker._worker_number)
     241        driver.start()
     242
     243        class SingleTestThread(threading.Thread):
     244            def run(self):
     245                self.result = worker._run_single_test(driver, test_input)
     246
     247        thread = SingleTestThread()
     248        thread.start()
     249        thread.join(thread_timeout_sec)
     250        result = getattr(thread, 'result', None)
     251        if thread.isAlive():
     252            # If join() returned with the thread still running, the
     253            # DumpRenderTree is completely hung and there's nothing
     254            # more we can do with it.  We have to kill all the
     255            # DumpRenderTrees to free it up. If we're running more than
     256            # one DumpRenderTree thread, we'll end up killing the other
     257            # DumpRenderTrees too, introducing spurious crashes. We accept
     258            # that tradeoff in order to avoid losing the rest of this
     259            # thread's results.
     260            _log.error('Test thread hung: killing all DumpRenderTrees')
     261
     262        driver.stop()
     263
     264        if not result:
     265            result = test_results.TestResult(test_input.filename, failures=[], test_run_time=0)
     266        return result
     267
     268    def _run_test_in_this_thread(self, test_input):
     269        """Run a single test file using a shared DumpRenderTree process.
     270
     271        Args:
     272          test_input: Object containing the test filename, uri and timeout
     273
     274        Returns: a TestResult object.
     275        """
     276        # poll() is not threadsafe and can throw OSError due to:
     277        # http://bugs.python.org/issue1731717
     278        if not self._driver or self._driver.poll() is not None:
     279            self._driver = self._port.create_driver(self._worker_number)
     280            self._driver.start()
     281        return self._run_single_test(self._driver, test_input)
     282
     283    def _run_single_test(self, driver, test_input):
     284        return single_test_runner.run_single_test(self._port, self._options,
     285            test_input, driver, self._name)
Note: See TracChangeset for help on using the changeset viewer.