| OLD | NEW |
| 1 # Copyright (C) 2011 Google Inc. All rights reserved. | 1 # Copyright (C) 2011 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| 11 # in the documentation and/or other materials provided with the | 11 # in the documentation and/or other materials provided with the |
| 12 # distribution. | 12 # distribution. |
| 13 # * Neither the name of Google Inc. nor the names of its | 13 # * Neither the name of Google Inc. nor the names of its |
| 14 # contributors may be used to endorse or promote products derived from | 14 # contributors may be used to endorse or promote products derived from |
| 15 # this software without specific prior written permission. | 15 # this software without specific prior written permission. |
| 16 # | 16 # |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | 28 |
| 29 """Base class with common routines between the Apache, Lighttpd, and websocket s
ervers.""" | 29 """Base class used to start servers used by the layout tests.""" |
| 30 | 30 |
| 31 import errno | 31 import errno |
| 32 import logging | 32 import logging |
| 33 import socket | 33 import socket |
| 34 import sys | 34 import sys |
| 35 import tempfile | 35 import tempfile |
| 36 import time | 36 import time |
| 37 | 37 |
| 38 | 38 |
| 39 _log = logging.getLogger(__name__) | 39 _log = logging.getLogger(__name__) |
| 40 | 40 |
| 41 | 41 |
| 42 class ServerError(Exception): | 42 class ServerError(Exception): |
| 43 pass | 43 pass |
| 44 | 44 |
| 45 | 45 |
| 46 class ServerBase(object): | 46 class ServerBase(object): |
| 47 """A skeleton class for starting and stopping servers used by the layout tes
ts.""" | 47 """A skeleton class for starting and stopping servers used by the layout tes
ts.""" |
| 48 | 48 |
| 49 def __init__(self, port_obj, number_of_servers=None): | 49 def __init__(self, port_obj, output_dir): |
| 50 self._port_obj = port_obj |
| 50 self._executive = port_obj._executive | 51 self._executive = port_obj._executive |
| 51 self._filesystem = port_obj._filesystem | 52 self._filesystem = port_obj._filesystem |
| 52 self._name = '<virtual>' | 53 self._output_dir = output_dir |
| 53 self._mappings = {} | |
| 54 self._pid = None | |
| 55 self._pid_file = None | |
| 56 self._port_obj = port_obj | |
| 57 self._number_of_servers = number_of_servers | |
| 58 | 54 |
| 59 # We need a non-checkout-dependent place to put lock files, etc. We | 55 # We need a non-checkout-dependent place to put lock files, etc. We |
| 60 # don't use the Python default on the Mac because it defaults to a | 56 # don't use the Python default on the Mac because it defaults to a |
| 61 # randomly-generated directory under /var/folders and no one would ever | 57 # randomly-generated directory under /var/folders and no one would ever |
| 62 # look there. | 58 # look there. |
| 63 tmpdir = tempfile.gettempdir() | 59 tmpdir = tempfile.gettempdir() |
| 64 if port_obj.host.platform.is_mac(): | 60 if port_obj.host.platform.is_mac(): |
| 65 tmpdir = '/tmp' | 61 tmpdir = '/tmp' |
| 66 | 62 |
| 67 self._runtime_path = self._filesystem.join(tmpdir, "WebKit") | 63 self._runtime_path = self._filesystem.join(tmpdir, "WebKit") |
| 68 self._filesystem.maybe_make_directory(self._runtime_path) | 64 self._filesystem.maybe_make_directory(self._runtime_path) |
| 69 | 65 |
| 66 # Subclasses must override these fields. |
| 67 self._name = '<virtual>' |
| 68 self._log_prefixes = tuple() |
| 69 self._mappings = {} |
| 70 self._pid_file = None |
| 71 self._start_cmd = None |
| 72 |
| 73 # Subclasses may override these fields. |
| 74 self._env = None |
| 75 self._stdout = self._executive.PIPE |
| 76 self._stderr = self._executive.PIPE |
| 77 self._process = None |
| 78 self._pid = None |
| 79 |
| 70 def start(self): | 80 def start(self): |
| 71 """Starts the server. It is an error to start an already started server. | 81 """Starts the server. It is an error to start an already started server. |
| 72 | 82 |
| 73 This method also stops any stale servers started by a previous instance.
""" | 83 This method also stops any stale servers started by a previous instance.
""" |
| 74 assert not self._pid, '%s server is already running' % self._name | 84 assert not self._pid, '%s server is already running' % self._name |
| 75 | 85 |
| 76 # Stop any stale servers left over from previous instances. | 86 # Stop any stale servers left over from previous instances. |
| 77 if self._filesystem.exists(self._pid_file): | 87 if self._filesystem.exists(self._pid_file): |
| 78 try: | 88 try: |
| 79 self._pid = int(self._filesystem.read_text_file(self._pid_file)) | 89 self._pid = int(self._filesystem.read_text_file(self._pid_file)) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 def _prepare_config(self): | 143 def _prepare_config(self): |
| 134 """This routine can be overridden by subclasses to do any sort | 144 """This routine can be overridden by subclasses to do any sort |
| 135 of initialization required prior to starting the server that may fail.""
" | 145 of initialization required prior to starting the server that may fail.""
" |
| 136 pass | 146 pass |
| 137 | 147 |
| 138 def _remove_stale_logs(self): | 148 def _remove_stale_logs(self): |
| 139 """This routine can be overridden by subclasses to try and remove logs | 149 """This routine can be overridden by subclasses to try and remove logs |
| 140 left over from a prior run. This routine should log warnings if the | 150 left over from a prior run. This routine should log warnings if the |
| 141 files cannot be deleted, but should not fail unless failure to | 151 files cannot be deleted, but should not fail unless failure to |
| 142 delete the logs will actually cause start() to fail.""" | 152 delete the logs will actually cause start() to fail.""" |
| 143 pass | 153 # Sometimes logs are open in other processes but they should clear event
ually. |
| 154 for log_prefix in self._log_prefixes: |
| 155 try: |
| 156 self._remove_log_files(self._output_dir, log_prefix) |
| 157 except OSError, e: |
| 158 _log.warning('Failed to remove old %s %s files' % (self._name, l
og_prefix)) |
| 144 | 159 |
| 145 def _spawn_process(self): | 160 def _spawn_process(self): |
| 146 """This routine must be implemented by subclasses to actually start the
server. | 161 _log.debug('Starting %s server, cmd="%s"' % (self._name, self._start_cmd
)) |
| 147 | 162 process = self._executive.popen(self._start_cmd, env=self._env, stdout=s
elf._stdout, stderr=self._stderr) |
| 148 This routine returns the pid of the started process, and also ensures th
at that | 163 pid = process.pid |
| 149 pid has been written to self._pid_file.""" | 164 self._filesystem.write_text_file(self._pid_file, str(pid)) |
| 150 raise NotImplementedError() | 165 return pid |
| 151 | 166 |
| 152 def _stop_running_server(self): | 167 def _stop_running_server(self): |
| 153 """This routine must be implemented by subclasses to actually stop the r
unning server listed in self._pid_file.""" | 168 self._wait_for_action(self._check_and_kill) |
| 154 raise NotImplementedError() | 169 if self._filesystem.exists(self._pid_file): |
| 170 self._filesystem.remove(self._pid_file) |
| 155 | 171 |
| 156 # Utility routines. | 172 def _check_and_kill(self): |
| 173 if self._executive.check_running_pid(self._pid): |
| 174 host = self._port_obj.host |
| 175 self._executive.kill_process(self._pid) |
| 176 return False |
| 177 return True |
| 157 | 178 |
| 158 def _remove_pid_file(self): | 179 def _remove_pid_file(self): |
| 159 if self._filesystem.exists(self._pid_file): | 180 if self._filesystem.exists(self._pid_file): |
| 160 self._filesystem.remove(self._pid_file) | 181 self._filesystem.remove(self._pid_file) |
| 161 | 182 |
| 162 def _remove_log_files(self, folder, starts_with): | 183 def _remove_log_files(self, folder, starts_with): |
| 163 files = self._filesystem.listdir(folder) | 184 files = self._filesystem.listdir(folder) |
| 164 for file in files: | 185 for file in files: |
| 165 if file.startswith(starts_with): | 186 if file.startswith(starts_with): |
| 166 full_path = self._filesystem.join(folder, file) | 187 full_path = self._filesystem.join(folder, file) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 s.bind(('localhost', port)) | 229 s.bind(('localhost', port)) |
| 209 except IOError, e: | 230 except IOError, e: |
| 210 if e.errno in (errno.EALREADY, errno.EADDRINUSE): | 231 if e.errno in (errno.EALREADY, errno.EADDRINUSE): |
| 211 raise ServerError('Port %d is already in use.' % port) | 232 raise ServerError('Port %d is already in use.' % port) |
| 212 elif sys.platform == 'win32' and e.errno in (errno.WSAEACCES,):
# pylint: disable=E1101 | 233 elif sys.platform == 'win32' and e.errno in (errno.WSAEACCES,):
# pylint: disable=E1101 |
| 213 raise ServerError('Port %d is already in use.' % port) | 234 raise ServerError('Port %d is already in use.' % port) |
| 214 else: | 235 else: |
| 215 raise | 236 raise |
| 216 finally: | 237 finally: |
| 217 s.close() | 238 s.close() |
| OLD | NEW |