[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

ossy at webkit.org ossy at webkit.org
Wed Dec 22 14:31:33 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 92899e094b10e90bdeee6ab34cc0df3fd93b41a6
Author: ossy at webkit.org <ossy at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Oct 12 13:53:57 2010 +0000

    Implement http locking in NRWT.
    https://bugs.webkit.org/show_bug.cgi?id=47072
    
    Patch by Gabor Rapcsanyi <rgabor at inf.u-szeged.hu> on 2010-10-12
    Reviewed by Tony Chang.
    
    * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
    * Scripts/webkitpy/layout_tests/port/base.py:
    * Scripts/webkitpy/layout_tests/port/http_lock.py: Added.
    * Scripts/webkitpy/layout_tests/port/http_lock_unittest.py: Added.
    * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@69578 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 14a6c9f..3a08342 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,16 @@
+2010-10-12  Gabor Rapcsanyi  <rgabor at inf.u-szeged.hu>
+
+        Reviewed by Tony Chang.
+
+        Implement http locking in NRWT.
+        https://bugs.webkit.org/show_bug.cgi?id=47072
+
+        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+        * Scripts/webkitpy/layout_tests/port/base.py:
+        * Scripts/webkitpy/layout_tests/port/http_lock.py: Added.
+        * Scripts/webkitpy/layout_tests/port/http_lock_unittest.py: Added.
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
 2010-10-12  Mark Rowe  <mrowe at apple.com>
 
         Fix the 32-bit WebKit2 build.
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 f1eb0bf..e0fd1b6 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
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 # Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor at inf.u-szeged.hu), University of Szeged
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
@@ -276,6 +277,9 @@ class TestShellThread(WatchableThread):
         self._num_tests = 0
         self._start_time = 0
         self._stop_time = 0
+        self._have_http_lock = False
+        self._http_lock_wait_begin = 0
+        self._http_lock_wait_end = 0
 
         # Current group of tests we're running.
         self._current_group = None
@@ -298,7 +302,8 @@ class TestShellThread(WatchableThread):
         return self._test_results
 
     def get_total_time(self):
-        return max(self._stop_time - self._start_time, 0.0)
+        return max(self._stop_time - self._start_time -
+                   self._http_lock_wait_time(), 0.0)
 
     def get_num_tests(self):
         return self._num_tests
@@ -337,6 +342,25 @@ class TestShellThread(WatchableThread):
         do multi-threaded debugging."""
         self._run(test_runner, result_summary)
 
+    def cancel(self):
+        """Clean up http lock and set a flag telling this thread to quit."""
+        self._stop_http_lock()
+        WatchableThread.cancel(self)
+
+    def next_timeout(self):
+        """Return the time the test is supposed to finish by."""
+        if self._next_timeout:
+            return self._next_timeout + self._http_lock_wait_time()
+        return self._next_timeout
+
+    def _http_lock_wait_time(self):
+        """Return the time what http locking takes."""
+        if self._http_lock_wait_begin == 0:
+            return 0
+        if self._http_lock_wait_end == 0:
+            return time.time() - self._http_lock_wait_begin
+        return self._http_lock_wait_end - self._http_lock_wait_begin
+
     def _run(self, test_runner, result_summary):
         """Main work entry point of the thread. Basically we pull urls from the
         filename queue and run the tests until we run out of urls.
@@ -368,10 +392,24 @@ class TestShellThread(WatchableThread):
                     self._current_group, self._filename_list = \
                         self._filename_list_queue.get_nowait()
                 except Queue.Empty:
+                    self._stop_http_lock()
                     self._kill_dump_render_tree()
                     tests_run_file.close()
                     return
 
+                if self._options.wait_for_httpd:
+                    if self._current_group == "tests_to_http_lock":
+                        self._http_lock_wait_begin = time.time()
+                        self._port.acquire_http_lock()
+
+                        self._port.start_http_server()
+                        self._port.start_websocket_server()
+
+                        self._have_http_lock = True
+                        self._http_lock_wait_end = time.time()
+                    elif self._have_http_lock:
+                        self._stop_http_lock()
+
                 self._num_tests_in_current_group = len(self._filename_list)
                 self._current_group_start_time = time.time()
 
@@ -517,6 +555,14 @@ class TestShellThread(WatchableThread):
                                                     self._options)
             self._driver.start()
 
+    def _stop_http_lock(self):
+        """Stop the servers and release http lock."""
+        if self._have_http_lock:
+            self._port.stop_http_server()
+            self._port.stop_websocket_server()
+            self._port.release_http_lock()
+            self._have_http_lock = False
+
     def _kill_dump_render_tree(self):
         """Kill the DumpRenderTree process if it's running."""
         if self._driver:
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
index 56ca0ca..38b982b 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
@@ -42,8 +42,9 @@ import sys
 import time
 
 import apache_http_server
-import test_files
+import http_lock
 import http_server
+import test_files
 import websocket_server
 
 from webkitpy.common.system import logutils
@@ -92,6 +93,7 @@ class Port(object):
         self._http_server = None
         self._webkit_base_dir = None
         self._websocket_server = None
+        self._http_lock = None
 
     def default_child_processes(self):
         """Return the number of DumpRenderTree instances to use for this
@@ -500,6 +502,10 @@ class Port(object):
             self._options.results_directory)
         self._websocket_server.start()
 
+    def acquire_http_lock(self):
+        self._http_lock = http_lock.HttpLock(None)
+        self._http_lock.wait_for_httpd_lock()
+
     def stop_helper(self):
         """Shut down the test helper if it is running. Do nothing if
         it isn't, or it isn't available. If a port overrides start_helper()
@@ -518,6 +524,10 @@ class Port(object):
         if self._websocket_server:
             self._websocket_server.stop()
 
+    def release_http_lock(self):
+        if self._http_lock:
+            self._http_lock.cleanup_http_lock()
+
     def test_expectations(self):
         """Returns the test expectations for this port.
 
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py
new file mode 100644
index 0000000..d4b5682
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor at inf.u-szeged.hu), University of Szeged
+# Copyright (C) 2010 Andras Becsi (abecsi at inf.u-szeged.hu), University of Szeged
+#
+# All rights reserved.
+#
+# 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+
+"""This class helps to block NRWT threads when more NRWTs run
+http and websocket tests in a same time."""
+
+import fcntl
+import glob
+import os
+import signal
+import sys
+import tempfile
+import time
+
+
+class HttpLock(object):
+
+    def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.",
+                 guard_lock="WebKit.lock"):
+        if not lock_path:
+            self._lock_path = tempfile.gettempdir()
+        self._lock_file_prefix = lock_file_prefix
+        self._lock_file_path_prefix = os.path.join(self._lock_path,
+                                                   self._lock_file_prefix)
+        self._guard_lock_file = os.path.join(self._lock_path, guard_lock)
+        self._process_lock_file_name = ""
+
+    def cleanup_http_lock(self):
+        """Delete the lock file if exists."""
+        if os.path.exists(self._process_lock_file_name):
+            os.unlink(self._process_lock_file_name)
+
+    def _extract_lock_number(self, lock_file_name):
+        """Return the lock number from lock file."""
+        prefix_length = len(self._lock_file_path_prefix)
+        return int(lock_file_name[prefix_length:])
+
+    def _lock_file_list(self):
+        """Return the list of lock files sequentially."""
+        lock_list = glob.glob(self._lock_file_path_prefix + '*')
+        lock_list.sort(key=self._extract_lock_number)
+        return lock_list
+
+    def _next_lock_number(self):
+        """Return the next available lock number."""
+        lock_list = self._lock_file_list()
+        if not lock_list:
+            return 0
+        return self._extract_lock_number(lock_list[-1]) + 1
+
+    def _check_pid(self, current_pid):
+        """Return True if pid is alive, otherwise return False."""
+        try:
+            os.kill(current_pid, 0)
+        except OSError:
+            return False
+        else:
+            return True
+
+    def _curent_lock_pid(self):
+        """Return with the current lock pid. If the lock is not valid
+        it deletes the lock file."""
+        lock_list = self._lock_file_list()
+        if not lock_list:
+            return
+        try:
+            current_lock_file = open(lock_list[0], 'r')
+            current_pid = current_lock_file.readline()
+            current_lock_file.close()
+            if not (current_pid and
+              sys.platform in ('darwin', 'linux2') and
+              self._check_pid(int(current_pid))):
+                os.unlink(lock_list[0])
+                return
+        except IOError, OSError:
+            return
+        return int(current_pid)
+
+    def _create_lock_file(self):
+        """The lock files are used to schedule the running test sessions in first
+        come first served order. The sequential guard lock ensures that the lock
+        numbers are sequential."""
+        while(True):
+            try:
+                sequential_guard_lock = os.open(self._guard_lock_file,
+                                                os.O_CREAT | os.O_NONBLOCK | os.O_EXCL)
+
+                self._process_lock_file_name = (self._lock_file_path_prefix +
+                                                str(self._next_lock_number()))
+                lock_file = open(self._process_lock_file_name, 'w')
+                lock_file.write(str(os.getpid()))
+                lock_file.close()
+                os.close(sequential_guard_lock)
+                os.unlink(self._guard_lock_file)
+                break
+            except OSError:
+                pass
+
+    def wait_for_httpd_lock(self):
+        """Create a lock file and wait until it's turn comes."""
+        self._create_lock_file()
+        while self._curent_lock_pid() != os.getpid():
+            time.sleep(1)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py
new file mode 100644
index 0000000..f2e4ce5
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor at inf.u-szeged.hu), University of Szeged
+#
+# All rights reserved.
+#
+# 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+
+import glob
+import http_lock
+import os
+import unittest
+
+
+class HttpLockTest(unittest.TestCase):
+
+    def __init__(self, testFunc):
+        self.http_lock_obj = http_lock.HttpLock(None, "WebKitTestHttpd.lock.", "WebKitTest.lock")
+        self.lock_file_path_prefix = os.path.join(self.http_lock_obj._lock_path,
+                                                  self.http_lock_obj._lock_file_prefix)
+        self.lock_file_name = self.lock_file_path_prefix + "0"
+        self.guard_lock_file = self.http_lock_obj._guard_lock_file
+        self.clean_all_lockfile()
+        unittest.TestCase.__init__(self, testFunc)
+
+    def clean_all_lockfile(self):
+        if os.path.exists(self.guard_lock_file):
+            os.unlink(guard_lock_file)
+        lock_list = glob.glob(self.lock_file_path_prefix + '*')
+        for file_name in lock_list:
+            os.unlink(file_name)
+
+    def assertEqual(self, first, second):
+        if first != second:
+            self.clean_all_lockfile()
+        unittest.TestCase.assertEqual(self, first, second)
+
+    def _check_lock_file(self):
+        if os.path.exists(self.lock_file_name):
+            pid = os.getpid()
+            lock_file = open(self.lock_file_name, 'r')
+            lock_file_pid = lock_file.readline()
+            lock_file.close()
+            self.assertEqual(pid, int(lock_file_pid))
+            return True
+        return False
+
+    def test_lock_lifecycle(self):
+        self.http_lock_obj._create_lock_file()
+
+        self.assertEqual(True, self._check_lock_file())
+        self.assertEqual(1, self.http_lock_obj._next_lock_number())
+
+        self.http_lock_obj.cleanup_http_lock()
+
+        self.assertEqual(False, self._check_lock_file())
+        self.assertEqual(0, self.http_lock_obj._next_lock_number())
+
+    def test_extract_lock_number(self,):
+        lock_file_list = (
+            self.lock_file_path_prefix + "00",
+            self.lock_file_path_prefix + "9",
+            self.lock_file_path_prefix + "001",
+            self.lock_file_path_prefix + "021",
+        )
+
+        expected_number_list = (0, 9, 1, 21)
+
+        for lock_file, expected in zip(lock_file_list, expected_number_list):
+            self.assertEqual(self.http_lock_obj._extract_lock_number(lock_file), expected)
+
+    def test_lock_file_list(self):
+        lock_file_list = [
+            self.lock_file_path_prefix + "6",
+            self.lock_file_path_prefix + "1",
+            self.lock_file_path_prefix + "4",
+            self.lock_file_path_prefix + "3",
+        ]
+
+        expected_file_list = [
+            self.lock_file_path_prefix + "1",
+            self.lock_file_path_prefix + "3",
+            self.lock_file_path_prefix + "4",
+            self.lock_file_path_prefix + "6",
+        ]
+
+        for file_name in lock_file_list:
+            open(file_name, 'w')
+
+        self.assertEqual(self.http_lock_obj._lock_file_list(), expected_file_list)
+
+        for file_name in lock_file_list:
+            os.unlink(file_name)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index cf637ee..9cc7895 100755
--- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -704,6 +704,10 @@ class TestRunner:
         """Returns whether the test runner needs an HTTP server."""
         return self._contains_tests(self.HTTP_SUBDIR)
 
+    def needs_websocket(self):
+        """Returns whether the test runner needs a WEBSOCKET server."""
+        return self._contains_tests(self.WEBSOCKET_SUBDIR)
+
     def set_up_run(self):
         """Configures the system to be ready to run tests.
 
@@ -736,14 +740,16 @@ class TestRunner:
         if not result_summary:
             return None
 
-        if self.needs_http():
-            self._printer.print_update('Starting HTTP server ...')
-            self._port.start_http_server()
+        # Do not start when http locking is enabled.
+        if not self._options.wait_for_httpd:
+            if self.needs_http():
+                self._printer.print_update('Starting HTTP server ...')
+                self._port.start_http_server()
 
-        if self._contains_tests(self.WEBSOCKET_SUBDIR):
-            self._printer.print_update('Starting WebSocket server ...')
-            self._port.start_websocket_server()
-            # self._websocket_secure_server.Start()
+            if self.needs_websocket():
+                self._printer.print_update('Starting WebSocket server ...')
+                self._port.start_websocket_server()
+                # self._websocket_secure_server.Start()
 
         return result_summary
 
@@ -834,10 +840,11 @@ class TestRunner:
         sys.stdout.flush()
         _log.debug("flushing stderr")
         sys.stderr.flush()
-        _log.debug("stopping http server")
-        self._port.stop_http_server()
-        _log.debug("stopping websocket server")
-        self._port.stop_websocket_server()
+        if not self._options.wait_for_httpd:
+            _log.debug("stopping http server")
+            self._port.stop_http_server()
+            _log.debug("stopping websocket server")
+            self._port.stop_websocket_server()
         _log.debug("stopping helper")
         self._port.stop_helper()
 
@@ -1593,13 +1600,12 @@ def parse_args(args=None):
         optparse.make_option("--no-record-results", action="store_false",
             default=True, dest="record_results",
             help="Don't record the results."),
+        optparse.make_option("--wait-for-httpd", action="store_true",
+            default=False, dest="wait_for_httpd",
+            help="Wait for http locks."),
         # old-run-webkit-tests also has HTTP toggle options:
         # --[no-]http                     Run (or do not run) http tests
         #                                 (default: run)
-        # --[no-]wait-for-httpd           Wait for httpd if some other test
-        #                                 session is using it already (same
-        #                                 as WEBKIT_WAIT_FOR_HTTPD=1).
-        #                                 (default: 0)
     ]
 
     test_options = [

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list