OLD | NEW |
| (Empty) |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Host driven test server controller. | |
6 | |
7 This class controls the startup and shutdown of a python driven test server that | |
8 runs in a separate process. | |
9 | |
10 The server starts up automatically when the object is created. | |
11 | |
12 After it starts up, it is possible to retreive the hostname it started on | |
13 through accessing the member field |host| and the port name through |port|. | |
14 | |
15 For shutting down the server, call TearDown(). | |
16 """ | |
17 | |
18 import logging | |
19 import subprocess | |
20 import os | |
21 import os.path | |
22 import time | |
23 import urllib2 | |
24 | |
25 from pylib import constants | |
26 from pylib.constants import host_paths | |
27 | |
28 # NOTE: when adding or modifying these lines, omit any leading slashes! | |
29 # Otherwise os.path.join() will (correctly) treat them as absolute paths | |
30 # instead of relative paths, and will do nothing. | |
31 _PYTHONPATH_DIRS = [ | |
32 'net/tools/testserver/', | |
33 'third_party/', | |
34 'third_party/pyftpdlib/src/', | |
35 'third_party/pywebsocket/src', | |
36 'third_party/tlslite/', | |
37 ] | |
38 | |
39 # Python files in these directories are generated as part of the build. | |
40 # These dirs are located in out/(Debug|Release) directory. | |
41 # The correct path is determined based on the build type. E.g. out/Debug for | |
42 # debug builds and out/Release for release builds. | |
43 _GENERATED_PYTHONPATH_DIRS = [ | |
44 'pyproto/policy/proto/', | |
45 'pyproto/sync/protocol/', | |
46 'pyproto/' | |
47 ] | |
48 | |
49 _TEST_SERVER_HOST = '127.0.0.1' | |
50 # Paths for supported test server executables. | |
51 TEST_NET_SERVER_PATH = 'net/tools/testserver/testserver.py' | |
52 TEST_SYNC_SERVER_PATH = 'sync/tools/testserver/sync_testserver.py' | |
53 TEST_POLICY_SERVER_PATH = 'chrome/browser/policy/test/policy_testserver.py' | |
54 # Parameters to check that the server is up and running. | |
55 TEST_SERVER_CHECK_PARAMS = { | |
56 TEST_NET_SERVER_PATH: { | |
57 'url_path': '/', | |
58 'response': 'Default response given for path' | |
59 }, | |
60 TEST_SYNC_SERVER_PATH: { | |
61 'url_path': 'chromiumsync/time', | |
62 'response': '0123456789' | |
63 }, | |
64 TEST_POLICY_SERVER_PATH: { | |
65 'url_path': 'test/ping', | |
66 'response': 'Policy server is up.' | |
67 }, | |
68 } | |
69 | |
70 class TestServer(object): | |
71 """Sets up a host driven test server on the host machine. | |
72 | |
73 For shutting down the server, call TearDown(). | |
74 """ | |
75 | |
76 def __init__(self, shard_index, test_server_port, test_server_path, | |
77 test_server_flags=None): | |
78 """Sets up a Python driven test server on the host machine. | |
79 | |
80 Args: | |
81 shard_index: Index of the current shard. | |
82 test_server_port: Port to run the test server on. This is multiplexed with | |
83 the shard index. To retrieve the real port access the | |
84 member variable |port|. | |
85 test_server_path: The path (relative to the root src dir) of the server | |
86 test_server_flags: Optional list of additional flags to the test server | |
87 """ | |
88 self.host = _TEST_SERVER_HOST | |
89 self.port = test_server_port + shard_index | |
90 | |
91 src_dir = host_paths.DIR_SOURCE_ROOT | |
92 # Make dirs into a list of absolute paths. | |
93 abs_dirs = [os.path.join(src_dir, d) for d in _PYTHONPATH_DIRS] | |
94 # Add the generated python files to the path | |
95 abs_dirs.extend([os.path.join(src_dir, constants.GetOutDirectory(), d) | |
96 for d in _GENERATED_PYTHONPATH_DIRS]) | |
97 current_python_path = os.environ.get('PYTHONPATH') | |
98 extra_python_path = ':'.join(abs_dirs) | |
99 if current_python_path: | |
100 python_path = current_python_path + ':' + extra_python_path | |
101 else: | |
102 python_path = extra_python_path | |
103 | |
104 # NOTE: A separate python process is used to simplify getting the right | |
105 # system path for finding includes. | |
106 test_server_flags = test_server_flags or [] | |
107 cmd = ['python', os.path.join(src_dir, test_server_path), | |
108 '--log-to-console', | |
109 ('--host=%s' % self.host), | |
110 ('--port=%d' % self.port), | |
111 '--on-remote-server'] + test_server_flags | |
112 self._test_server_process = subprocess.Popen( | |
113 cmd, env={'PYTHONPATH': python_path}) | |
114 test_url = 'http://%s:%d/%s' % (self.host, self.port, | |
115 TEST_SERVER_CHECK_PARAMS[test_server_path]['url_path']) | |
116 expected_response = TEST_SERVER_CHECK_PARAMS[test_server_path]['response'] | |
117 retries = 0 | |
118 while retries < 5: | |
119 try: | |
120 d = urllib2.urlopen(test_url).read() | |
121 logging.info('URL %s GOT: %s', test_url, d) | |
122 if d.startswith(expected_response): | |
123 break | |
124 except Exception as e: # pylint: disable=broad-except | |
125 logging.info('URL %s GOT: %s', test_url, e) | |
126 time.sleep(retries * 0.1) | |
127 retries += 1 | |
128 | |
129 def TearDown(self): | |
130 self._test_server_process.kill() | |
131 self._test_server_process.wait() | |
OLD | NEW |