Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: Tools/Scripts/webkitpy/layout_tests/servers/server_base.py

Issue 159723008: Refactor webkitpy.layout_tests.servers.server_base. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698