OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """A "Test Server Spawner" that handles killing/stopping per-test test servers. | 5 """A "Test Server Spawner" that handles killing/stopping per-test test servers. |
6 | 6 |
7 It's used to accept requests from the device to spawn and kill instances of the | 7 It's used to accept requests from the device to spawn and kill instances of the |
8 chrome test server on the host. | 8 chrome test server on the host. |
9 """ | 9 """ |
10 | 10 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 raise NotImplementedError('Unknown server type: %s' % server_type) | 93 raise NotImplementedError('Unknown server type: %s' % server_type) |
94 if server_type == 'udpecho': | 94 if server_type == 'udpecho': |
95 raise Exception('Please do not run UDP echo tests because we do not have ' | 95 raise Exception('Please do not run UDP echo tests because we do not have ' |
96 'a UDP forwarder tool.') | 96 'a UDP forwarder tool.') |
97 return SERVER_TYPES[server_type] | 97 return SERVER_TYPES[server_type] |
98 | 98 |
99 | 99 |
100 class TestServerThread(threading.Thread): | 100 class TestServerThread(threading.Thread): |
101 """A thread to run the test server in a separate process.""" | 101 """A thread to run the test server in a separate process.""" |
102 | 102 |
103 def __init__(self, ready_event, arguments, adb, tool, build_type): | 103 def __init__(self, ready_event, arguments, adb, tool): |
104 """Initialize TestServerThread with the following argument. | 104 """Initialize TestServerThread with the following argument. |
105 | 105 |
106 Args: | 106 Args: |
107 ready_event: event which will be set when the test server is ready. | 107 ready_event: event which will be set when the test server is ready. |
108 arguments: dictionary of arguments to run the test server. | 108 arguments: dictionary of arguments to run the test server. |
109 adb: instance of AndroidCommands. | 109 adb: instance of AndroidCommands. |
110 tool: instance of runtime error detection tool. | 110 tool: instance of runtime error detection tool. |
111 build_type: 'Release' or 'Debug'. | |
112 """ | 111 """ |
113 threading.Thread.__init__(self) | 112 threading.Thread.__init__(self) |
114 self.wait_event = threading.Event() | 113 self.wait_event = threading.Event() |
115 self.stop_flag = False | 114 self.stop_flag = False |
116 self.ready_event = ready_event | 115 self.ready_event = ready_event |
117 self.ready_event.clear() | 116 self.ready_event.clear() |
118 self.arguments = arguments | 117 self.arguments = arguments |
119 self.adb = adb | 118 self.adb = adb |
120 self.tool = tool | 119 self.tool = tool |
121 self.test_server_process = None | 120 self.test_server_process = None |
122 self.is_ready = False | 121 self.is_ready = False |
123 self.host_port = self.arguments['port'] | 122 self.host_port = self.arguments['port'] |
124 assert isinstance(self.host_port, int) | 123 assert isinstance(self.host_port, int) |
125 # The forwarder device port now is dynamically allocated. | 124 # The forwarder device port now is dynamically allocated. |
126 self.forwarder_device_port = 0 | 125 self.forwarder_device_port = 0 |
127 # Anonymous pipe in order to get port info from test server. | 126 # Anonymous pipe in order to get port info from test server. |
128 self.pipe_in = None | 127 self.pipe_in = None |
129 self.pipe_out = None | 128 self.pipe_out = None |
130 self.command_line = [] | 129 self.command_line = [] |
131 self.build_type = build_type | |
132 | 130 |
133 def _WaitToStartAndGetPortFromTestServer(self): | 131 def _WaitToStartAndGetPortFromTestServer(self): |
134 """Waits for the Python test server to start and gets the port it is using. | 132 """Waits for the Python test server to start and gets the port it is using. |
135 | 133 |
136 The port information is passed by the Python test server with a pipe given | 134 The port information is passed by the Python test server with a pipe given |
137 by self.pipe_out. It is written as a result to |self.host_port|. | 135 by self.pipe_out. It is written as a result to |self.host_port|. |
138 | 136 |
139 Returns: | 137 Returns: |
140 Whether the port used by the test server was successfully fetched. | 138 Whether the port used by the test server was successfully fetched. |
141 """ | 139 """ |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 'testserver.py')] + self.command_line | 242 'testserver.py')] + self.command_line |
245 logging.info('Running: %s', command) | 243 logging.info('Running: %s', command) |
246 self.process = subprocess.Popen( | 244 self.process = subprocess.Popen( |
247 command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess) | 245 command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess) |
248 if self.process: | 246 if self.process: |
249 if self.pipe_out: | 247 if self.pipe_out: |
250 self.is_ready = self._WaitToStartAndGetPortFromTestServer() | 248 self.is_ready = self._WaitToStartAndGetPortFromTestServer() |
251 else: | 249 else: |
252 self.is_ready = _CheckPortStatus(self.host_port, True) | 250 self.is_ready = _CheckPortStatus(self.host_port, True) |
253 if self.is_ready: | 251 if self.is_ready: |
254 Forwarder.Map([(0, self.host_port)], self.adb, self.build_type, self.tool) | 252 Forwarder.Map([(0, self.host_port)], self.adb, constants.GetBuildType(), |
| 253 self.tool) |
255 # Check whether the forwarder is ready on the device. | 254 # Check whether the forwarder is ready on the device. |
256 self.is_ready = False | 255 self.is_ready = False |
257 device_port = Forwarder.DevicePortForHostPort(self.host_port) | 256 device_port = Forwarder.DevicePortForHostPort(self.host_port) |
258 if device_port and _CheckDevicePortStatus(self.adb, device_port): | 257 if device_port and _CheckDevicePortStatus(self.adb, device_port): |
259 self.is_ready = True | 258 self.is_ready = True |
260 self.forwarder_device_port = device_port | 259 self.forwarder_device_port = device_port |
261 # Wake up the request handler thread. | 260 # Wake up the request handler thread. |
262 self.ready_event.set() | 261 self.ready_event.set() |
263 # Keep thread running until Stop() gets called. | 262 # Keep thread running until Stop() gets called. |
264 _WaitUntil(lambda: self.stop_flag, max_attempts=sys.maxint) | 263 _WaitUntil(lambda: self.stop_flag, max_attempts=sys.maxint) |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 raise Exception('Bad content-length for start request.') | 325 raise Exception('Bad content-length for start request.') |
327 logging.info(content_length) | 326 logging.info(content_length) |
328 test_server_argument_json = self.rfile.read(content_length) | 327 test_server_argument_json = self.rfile.read(content_length) |
329 logging.info(test_server_argument_json) | 328 logging.info(test_server_argument_json) |
330 assert not self.server.test_server_instance | 329 assert not self.server.test_server_instance |
331 ready_event = threading.Event() | 330 ready_event = threading.Event() |
332 self.server.test_server_instance = TestServerThread( | 331 self.server.test_server_instance = TestServerThread( |
333 ready_event, | 332 ready_event, |
334 json.loads(test_server_argument_json), | 333 json.loads(test_server_argument_json), |
335 self.server.adb, | 334 self.server.adb, |
336 self.server.tool, | 335 self.server.tool) |
337 self.server.build_type) | |
338 self.server.test_server_instance.setDaemon(True) | 336 self.server.test_server_instance.setDaemon(True) |
339 self.server.test_server_instance.start() | 337 self.server.test_server_instance.start() |
340 ready_event.wait() | 338 ready_event.wait() |
341 if self.server.test_server_instance.is_ready: | 339 if self.server.test_server_instance.is_ready: |
342 self._SendResponse(200, 'OK', {}, json.dumps( | 340 self._SendResponse(200, 'OK', {}, json.dumps( |
343 {'port': self.server.test_server_instance.forwarder_device_port, | 341 {'port': self.server.test_server_instance.forwarder_device_port, |
344 'message': 'started'})) | 342 'message': 'started'})) |
345 logging.info('Test server is running on port: %d.', | 343 logging.info('Test server is running on port: %d.', |
346 self.server.test_server_instance.host_port) | 344 self.server.test_server_instance.host_port) |
347 else: | 345 else: |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 self._SendResponse(200, 'OK', {}, 'ready') | 392 self._SendResponse(200, 'OK', {}, 'ready') |
395 logging.info('Handled ping request and sent response.') | 393 logging.info('Handled ping request and sent response.') |
396 else: | 394 else: |
397 self._SendResponse(400, 'Unknown request', {}, '') | 395 self._SendResponse(400, 'Unknown request', {}, '') |
398 logging.info('Encounter unknown request: %s.', action) | 396 logging.info('Encounter unknown request: %s.', action) |
399 | 397 |
400 | 398 |
401 class SpawningServer(object): | 399 class SpawningServer(object): |
402 """The class used to start/stop a http server.""" | 400 """The class used to start/stop a http server.""" |
403 | 401 |
404 def __init__(self, test_server_spawner_port, adb, tool, build_type): | 402 def __init__(self, test_server_spawner_port, adb, tool): |
405 logging.info('Creating new spawner on port: %d.', test_server_spawner_port) | 403 logging.info('Creating new spawner on port: %d.', test_server_spawner_port) |
406 self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port), | 404 self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port), |
407 SpawningServerRequestHandler) | 405 SpawningServerRequestHandler) |
408 self.server.adb = adb | 406 self.server.adb = adb |
409 self.server.tool = tool | 407 self.server.tool = tool |
410 self.server.test_server_instance = None | 408 self.server.test_server_instance = None |
411 self.server.build_type = build_type | 409 self.server.build_type = constants.GetBuildType() |
412 | 410 |
413 def _Listen(self): | 411 def _Listen(self): |
414 logging.info('Starting test server spawner') | 412 logging.info('Starting test server spawner') |
415 self.server.serve_forever() | 413 self.server.serve_forever() |
416 | 414 |
417 def Start(self): | 415 def Start(self): |
418 """Starts the test server spawner.""" | 416 """Starts the test server spawner.""" |
419 listener_thread = threading.Thread(target=self._Listen) | 417 listener_thread = threading.Thread(target=self._Listen) |
420 listener_thread.setDaemon(True) | 418 listener_thread.setDaemon(True) |
421 listener_thread.start() | 419 listener_thread.start() |
422 | 420 |
423 def Stop(self): | 421 def Stop(self): |
424 """Stops the test server spawner. | 422 """Stops the test server spawner. |
425 | 423 |
426 Also cleans the server state. | 424 Also cleans the server state. |
427 """ | 425 """ |
428 self.CleanupState() | 426 self.CleanupState() |
429 self.server.shutdown() | 427 self.server.shutdown() |
430 | 428 |
431 def CleanupState(self): | 429 def CleanupState(self): |
432 """Cleans up the spawning server state. | 430 """Cleans up the spawning server state. |
433 | 431 |
434 This should be called if the test server spawner is reused, | 432 This should be called if the test server spawner is reused, |
435 to avoid sharing the test server instance. | 433 to avoid sharing the test server instance. |
436 """ | 434 """ |
437 if self.server.test_server_instance: | 435 if self.server.test_server_instance: |
438 self.server.test_server_instance.Stop() | 436 self.server.test_server_instance.Stop() |
439 self.server.test_server_instance = None | 437 self.server.test_server_instance = None |
OLD | NEW |