Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / tvcm / temporary_dev_server.py
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.
4 import httplib
5 import os
6 import json
7 import re
8 import socket
9 import subprocess
10 import sys
11 import urlparse
12 import time
13
14 from tvcm import dev_server
15
16 def GetUnreservedAvailableLocalPort():
17   """Returns an available port on the system.
18
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.
21   """
22   tmp = socket.socket()
23   tmp.bind(('', 0))
24   port = tmp.getsockname()[1]
25   tmp.close()
26
27   return port
28
29 def WaitFor(condition, timeout):
30   """Waits for up to |timeout| secs for the function |condition| to return True.
31
32   Polling frequency is (elapsed_time / 10), with a min of .1s and max of 5s.
33
34   Returns:
35     Result of |condition| function (if present).
36   """
37   min_poll_interval =   0.1
38   max_poll_interval =   5
39   output_interval   = 300
40
41   def GetConditionString():
42     if condition.__name__ == '<lambda>':
43       try:
44         return inspect.getsource(condition).strip()
45       except IOError:
46         pass
47     return condition.__name__
48
49   start_time = time.time()
50   last_output_time = start_time
51   while True:
52     res = condition()
53     if res:
54       return res
55     now = time.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),
66                         max_poll_interval)
67     time.sleep(poll_interval)
68
69 class TemporaryDevServer(object):
70   def __init__(self):
71     self._port = None
72     self._server = None
73
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__), '..'))
78
79     self._server = subprocess.Popen(cmd, cwd=os.getcwd(),
80                                     env=env, stdout=subprocess.PIPE, stderr=sys.stderr)
81
82     port_re = re.compile(
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)
87       if m:
88         self._port = int(m.group('port'))
89         break
90     if not self._port:
91       raise Exception('Couldn\'t start')
92
93     def IsServerUp():
94       return not socket.socket().connect_ex(('localhost', self._port))
95     WaitFor(IsServerUp, 10)
96
97   @property
98   def port(self):
99     return self._port
100
101   def __del__(self):
102     self.Close()
103
104   def Close(self):
105     if self._server:
106       # TODO(tonyg): Should this block until it goes away?
107       if self._server.poll() == None:
108         self._server.kill()
109       self._server = None
110
111   @property
112   def url(self):
113     return 'http://localhost:%i/' % self._port
114
115   def Get(self, path, expected_response_code=200):
116     conn = httplib.HTTPConnection('localhost', self.port, True)
117     conn.connect()
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:
122       try:
123         resp_data = json.loads(resp_str)
124       except ValueError:
125         resp_data = {}
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)
130       else:
131         raise Exception('Expected status %i, got %i: %s', expected_response_code, resp.status, resp_str)
132     return resp_str
133
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)
137
138     conn = httplib.HTTPConnection('localhost', self.port, True)
139     conn.connect()
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')
147       assert False
148     return resp_str
149
150
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')
155
156     eval(text, {}, {'self': request.server})
157     data = 'ok'
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)
163
164 def SubprocessMain(args):
165   port=GetUnreservedAvailableLocalPort()
166   server = dev_server.DevServer(port=port, quiet=True)
167
168   server.AddPathHandler('/test/customize', _do_POST_customize,
169                         supports_get=False,
170                         supports_post=True)
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()
174
175 if __name__ == '__main__':
176   sys.exit(SubprocessMain(sys.argv[1:]))