1 # Copyright (c) 2012 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.
14 from tvcm import dev_server
16 def GetUnreservedAvailableLocalPort():
17 """Returns an available port on the system.
19 WARNING: This method does not reserve the port it returns, so it may be used
20 by something else before you get to use it. This can lead to flake.
24 port = tmp.getsockname()[1]
29 def WaitFor(condition, timeout):
30 """Waits for up to |timeout| secs for the function |condition| to return True.
32 Polling frequency is (elapsed_time / 10), with a min of .1s and max of 5s.
35 Result of |condition| function (if present).
37 min_poll_interval = 0.1
41 def GetConditionString():
42 if condition.__name__ == '<lambda>':
44 return inspect.getsource(condition).strip()
47 return condition.__name__
49 start_time = time.time()
50 last_output_time = start_time
56 elapsed_time = now - start_time
57 last_output_elapsed_time = now - last_output_time
58 if elapsed_time > timeout:
59 raise TimeoutException('Timed out while waiting %ds for %s.' %
60 (timeout, GetConditionString()))
61 if last_output_elapsed_time > output_interval:
62 logging.info('Continuing to wait %ds for %s. Elapsed: %ds.',
63 timeout, GetConditionString(), elapsed_time)
64 last_output_time = time.time()
65 poll_interval = min(max(elapsed_time / 10., min_poll_interval),
67 time.sleep(poll_interval)
69 class TemporaryDevServer(object):
74 cmd = [sys.executable, '-m', __name__]
75 env = os.environ.copy()
76 env['PYTHONPATH'] = os.path.abspath(
77 os.path.join(os.path.dirname(__file__), '..'))
79 self._server = subprocess.Popen(cmd, cwd=os.getcwd(),
80 env=env, stdout=subprocess.PIPE, stderr=sys.stderr)
83 'TemporaryDevServer started on port (?P<port>\d+)')
84 while self._server.poll() == None:
85 line = self._server.stdout.readline()
86 m = port_re.match(line)
88 self._port = int(m.group('port'))
91 raise Exception('Couldn\'t start')
94 return not socket.socket().connect_ex(('localhost', self._port))
95 WaitFor(IsServerUp, 10)
106 # TODO(tonyg): Should this block until it goes away?
107 if self._server.poll() == None:
113 return 'http://localhost:%i/' % self._port
115 def Get(self, path, expected_response_code=200):
116 conn = httplib.HTTPConnection('localhost', self.port, True)
118 conn.request('GET', path)
119 resp = conn.getresponse()
120 resp_str = resp.read(resp.getheader('Content-Length'))
121 if resp.status != expected_response_code:
123 resp_data = json.loads(resp_str)
126 if 'details' in resp_data:
127 sys.stderr.write(resp_data['details'])
128 sys.stderr.write('\n')
129 raise Exception('Expected status %i, got %i', expected_response_code, resp.status)
131 raise Exception('Expected status %i, got %i: %s', expected_response_code, resp.status, resp_str)
134 def CallOnServer(self, method_name, *args):
135 arg_string = ','.join([repr(arg) for arg in args])
136 data = 'self.%s(%s)' % (method_name, arg_string)
138 conn = httplib.HTTPConnection('localhost', self.port, True)
140 conn.request('POST', '/test/customize', data)
141 resp = conn.getresponse()
142 resp_str = resp.read(resp.getheader('Content-Length'))
143 if resp.status != 200:
144 resp_data = json.loads(resp_str)
145 sys.stderr.write(resp_data['details'])
146 sys.stderr.write('\n')
151 def _do_POST_customize(request):
152 if 'Content-Length' in request.headers:
153 cl = int(request.headers['Content-Length'])
154 text = request.rfile.read(cl).encode('utf8')
156 eval(text, {}, {'self': request.server})
158 request.send_response(200)
159 request.send_header('Content-Type', 'text/plain')
160 request.send_header('Content-Length', len(data))
161 request.end_headers()
162 request.wfile.write(data)
164 def SubprocessMain(args):
165 port=GetUnreservedAvailableLocalPort()
166 server = dev_server.DevServer(port=port, quiet=True)
168 server.AddPathHandler('/test/customize', _do_POST_customize,
171 sys.stdout.write('TemporaryDevServer started on port %i\n' % port)
172 sys.stdout.flush() # This is key! It kicks the port detector above.
173 server.serve_forever()
175 if __name__ == '__main__':
176 sys.exit(SubprocessMain(sys.argv[1:]))