| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # |
| 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 5 | 6 |
| 6 """Provides a convenient wrapper for spawning a test lighttpd instance. | 7 """Provides a convenient wrapper for spawning a test lighttpd instance. |
| 7 | 8 |
| 8 Usage: | 9 Usage: |
| 9 lighttpd_server PATH_TO_DOC_ROOT | 10 lighttpd_server PATH_TO_DOC_ROOT |
| 10 """ | 11 """ |
| 11 | 12 |
| 12 import codecs | 13 import codecs |
| 13 import contextlib | 14 import contextlib |
| 14 import httplib | 15 import httplib |
| 15 import os | 16 import os |
| 16 import pexpect | 17 import pexpect |
| 17 import random | 18 import random |
| 18 import shutil | 19 import shutil |
| 19 import socket | 20 import socket |
| 21 import subprocess |
| 20 import sys | 22 import sys |
| 21 import tempfile | 23 import tempfile |
| 24 import time |
| 25 |
| 26 from pylib import constants |
| 22 | 27 |
| 23 | 28 |
| 24 class LighttpdServer(object): | 29 class LighttpdServer(object): |
| 25 """Wraps lighttpd server, providing robust startup. | 30 """Wraps lighttpd server, providing robust startup. |
| 26 | 31 |
| 27 Args: | 32 Args: |
| 28 document_root: Path to root of this server's hosted files. | 33 document_root: Path to root of this server's hosted files. |
| 29 port: TCP port on the _host_ machine that the server will listen on. If | 34 port: TCP port on the _host_ machine that the server will listen on. If |
| 30 ommitted it will attempt to use 9000, or if unavailable it will find | 35 ommitted it will attempt to use 9000, or if unavailable it will find |
| 31 a free port from 8001 - 8999. | 36 a free port from 8001 - 8999. |
| 32 lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries. | 37 lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries. |
| 33 base_config_path: If supplied this file will replace the built-in default | 38 base_config_path: If supplied this file will replace the built-in default |
| 34 lighttpd config file. | 39 lighttpd config file. |
| 35 extra_config_contents: If specified, this string will be appended to the | 40 extra_config_contents: If specified, this string will be appended to the |
| 36 base config (default built-in, or from base_config_path). | 41 base config (default built-in, or from base_config_path). |
| 37 config_path, error_log, access_log: Optional paths where the class should | 42 config_path, error_log, access_log: Optional paths where the class should |
| 38 place temprary files for this session. | 43 place temprary files for this session. |
| 39 """ | 44 """ |
| 40 | 45 |
| 41 def __init__(self, document_root, port=None, | 46 def __init__(self, document_root, port=None, |
| 42 lighttpd_path=None, lighttpd_module_path=None, | 47 lighttpd_path=None, lighttpd_module_path=None, |
| 43 base_config_path=None, extra_config_contents=None, | 48 base_config_path=None, extra_config_contents=None, |
| 44 config_path=None, error_log=None, access_log=None): | 49 config_path=None, error_log=None, access_log=None): |
| 45 self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android') | 50 self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android') |
| 46 self.document_root = os.path.abspath(document_root) | 51 self.document_root = os.path.abspath(document_root) |
| 47 self.fixed_port = port | 52 self.fixed_port = port |
| 48 self.port = port or 9000 | 53 self.port = port or constants.LIGHTTPD_DEFAULT_PORT |
| 49 self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999)) | 54 self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999)) |
| 50 self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd' | 55 self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd' |
| 51 self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd' | 56 self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd' |
| 52 self.base_config_path = base_config_path | 57 self.base_config_path = base_config_path |
| 53 self.extra_config_contents = extra_config_contents | 58 self.extra_config_contents = extra_config_contents |
| 54 self.config_path = config_path or self._Mktmp('config') | 59 self.config_path = config_path or self._Mktmp('config') |
| 55 self.error_log = error_log or self._Mktmp('error_log') | 60 self.error_log = error_log or self._Mktmp('error_log') |
| 56 self.access_log = access_log or self._Mktmp('access_log') | 61 self.access_log = access_log or self._Mktmp('access_log') |
| 57 self.pid_file = self._Mktmp('pid_file') | 62 self.pid_file = self._Mktmp('pid_file') |
| 58 self.process = None | 63 self.process = None |
| 59 | 64 |
| 60 def _Mktmp(self, name): | 65 def _Mktmp(self, name): |
| 61 return os.path.join(self.temp_dir, name) | 66 return os.path.join(self.temp_dir, name) |
| 62 | 67 |
| 63 def _GetRandomPort(self): | 68 def _GetRandomPort(self): |
| 64 # Ports 8001-8004 are reserved for other test servers. Ensure we don't | 69 # The ports of test server is arranged in constants.py. |
| 65 # collide with them. | 70 return random.randint(constants.LIGHTTPD_RANDOM_PORT_FIRST, |
| 66 return random.randint(8005, 8999) | 71 constants.LIGHTTPD_RANDOM_PORT_LAST) |
| 67 | 72 |
| 68 def StartupHttpServer(self): | 73 def StartupHttpServer(self): |
| 69 """Starts up a http server with specified document root and port.""" | 74 """Starts up a http server with specified document root and port.""" |
| 70 # Currently we use lighttpd as http sever in test. | 75 # If we want a specific port, make sure no one else is listening on it. |
| 76 if self.fixed_port: |
| 77 self._KillProcessListeningOnPort(self.fixed_port) |
| 71 while True: | 78 while True: |
| 72 if self.base_config_path: | 79 if self.base_config_path: |
| 73 # Read the config | 80 # Read the config |
| 74 with codecs.open(self.base_config_path, 'r', 'utf-8') as f: | 81 with codecs.open(self.base_config_path, 'r', 'utf-8') as f: |
| 75 config_contents = f.read() | 82 config_contents = f.read() |
| 76 else: | 83 else: |
| 77 config_contents = self._GetDefaultBaseConfig() | 84 config_contents = self._GetDefaultBaseConfig() |
| 78 if self.extra_config_contents: | 85 if self.extra_config_contents: |
| 79 config_contents += self.extra_config_contents | 86 config_contents += self.extra_config_contents |
| 80 # Write out the config, filling in placeholders from the members of |self| | 87 # Write out the config, filling in placeholders from the members of |self| |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 # Check for server startup error messages | 139 # Check for server startup error messages |
| 133 ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'], | 140 ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'], |
| 134 timeout=timeout) | 141 timeout=timeout) |
| 135 if ix == 2: # stdout spew from the server | 142 if ix == 2: # stdout spew from the server |
| 136 server_msg += self.process.match.group(0) | 143 server_msg += self.process.match.group(0) |
| 137 elif ix == 1: # EOF -- server has quit so giveup. | 144 elif ix == 1: # EOF -- server has quit so giveup. |
| 138 client_error = client_error or 'Server exited' | 145 client_error = client_error or 'Server exited' |
| 139 break | 146 break |
| 140 return (client_error or 'Timeout', server_msg) | 147 return (client_error or 'Timeout', server_msg) |
| 141 | 148 |
| 149 def _KillProcessListeningOnPort(self, port): |
| 150 """Checks if there is a process listening on port number |port| and |
| 151 terminates it if found. |
| 152 |
| 153 Args: |
| 154 port: Port number to check. |
| 155 """ |
| 156 if subprocess.call(['fuser', '-kv', '%d/tcp' % port]) == 0: |
| 157 # Give the process some time to terminate and check that it is gone. |
| 158 time.sleep(2) |
| 159 assert subprocess.call(['fuser', '-v', '%d/tcp' % port]) != 0, \ |
| 160 'Unable to kill process listening on port %d.' % port |
| 161 |
| 142 def _GetDefaultBaseConfig(self): | 162 def _GetDefaultBaseConfig(self): |
| 143 return """server.tag = "%(server_tag)s" | 163 return """server.tag = "%(server_tag)s" |
| 144 server.modules = ( "mod_access", | 164 server.modules = ( "mod_access", |
| 145 "mod_accesslog", | 165 "mod_accesslog", |
| 146 "mod_alias", | 166 "mod_alias", |
| 147 "mod_cgi", | 167 "mod_cgi", |
| 148 "mod_rewrite" ) | 168 "mod_rewrite" ) |
| 149 | 169 |
| 150 # default document root required | 170 # default document root required |
| 151 #server.document-root = "." | 171 #server.document-root = "." |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 raw_input('Server running at http://127.0.0.1:%s -' | 245 raw_input('Server running at http://127.0.0.1:%s -' |
| 226 ' press Enter to exit it.' % server.port) | 246 ' press Enter to exit it.' % server.port) |
| 227 else: | 247 else: |
| 228 print 'Server exit code:', server.process.exitstatus | 248 print 'Server exit code:', server.process.exitstatus |
| 229 finally: | 249 finally: |
| 230 server.ShutdownHttpServer() | 250 server.ShutdownHttpServer() |
| 231 | 251 |
| 232 | 252 |
| 233 if __name__ == '__main__': | 253 if __name__ == '__main__': |
| 234 sys.exit(main(sys.argv)) | 254 sys.exit(main(sys.argv)) |
| OLD | NEW |