Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1470)

Side by Side Diff: build/android/pylib/chrome_test_server_spawner.py

Issue 634803002: Make host port availability detection more robust. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Allow reuseaddr before binding Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | build/android/pylib/ports.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 # pylint: disable=W0702 10 # pylint: disable=W0702
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 """ 57 """
58 sleep_time_sec = 0.025 58 sleep_time_sec = 0.025
59 for _ in xrange(1, max_attempts): 59 for _ in xrange(1, max_attempts):
60 if predicate(): 60 if predicate():
61 return True 61 return True
62 time.sleep(sleep_time_sec) 62 time.sleep(sleep_time_sec)
63 sleep_time_sec = min(1, sleep_time_sec * 2) # Don't wait more than 1 sec. 63 sleep_time_sec = min(1, sleep_time_sec * 2) # Don't wait more than 1 sec.
64 return False 64 return False
65 65
66 66
67 def _CheckPortStatus(port, expected_status): 67 def _CheckPortAvailable(port):
68 """Returns True if port has expected_status. 68 """Returns True if |port| is available."""
69 return _WaitUntil(lambda: ports.IsHostPortAvailable(port))
69 70
70 Args:
71 port: the port number.
72 expected_status: boolean of expected status.
73 71
74 Returns: 72 def _CheckPortNotAvailable(port):
75 Returns True if the status is expected. Otherwise returns False. 73 """Returns True if |port| is not available."""
76 """ 74 return _WaitUntil(lambda: not ports.IsHostPortAvailable(port))
77 return _WaitUntil(lambda: ports.IsHostPortUsed(port) == expected_status)
78 75
79 76
80 def _CheckDevicePortStatus(device, port): 77 def _CheckDevicePortStatus(device, port):
81 """Returns whether the provided port is used.""" 78 """Returns whether the provided port is used."""
82 return _WaitUntil(lambda: ports.IsDevicePortUsed(device, port)) 79 return _WaitUntil(lambda: ports.IsDevicePortUsed(device, port))
83 80
84 81
85 def _GetServerTypeCommandLine(server_type): 82 def _GetServerTypeCommandLine(server_type):
86 """Returns the command-line by the given server type. 83 """Returns the command-line by the given server type.
87 84
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 logging.error('Failed to get length of server data.') 157 logging.error('Failed to get length of server data.')
161 return False 158 return False
162 port_json = os.read(self.pipe_in, data_length) 159 port_json = os.read(self.pipe_in, data_length)
163 if not port_json: 160 if not port_json:
164 logging.error('Failed to get server data.') 161 logging.error('Failed to get server data.')
165 return False 162 return False
166 logging.info('Got port json data: %s', port_json) 163 logging.info('Got port json data: %s', port_json)
167 port_json = json.loads(port_json) 164 port_json = json.loads(port_json)
168 if port_json.has_key('port') and isinstance(port_json['port'], int): 165 if port_json.has_key('port') and isinstance(port_json['port'], int):
169 self.host_port = port_json['port'] 166 self.host_port = port_json['port']
170 return _CheckPortStatus(self.host_port, True) 167 return _CheckPortNotAvailable(self.host_port)
171 logging.error('Failed to get port information from the server data.') 168 logging.error('Failed to get port information from the server data.')
172 return False 169 return False
173 170
174 def _GenerateCommandLineArguments(self): 171 def _GenerateCommandLineArguments(self):
175 """Generates the command line to run the test server. 172 """Generates the command line to run the test server.
176 173
177 Note that all options are processed by following the definitions in 174 Note that all options are processed by following the definitions in
178 testserver.py. 175 testserver.py.
179 """ 176 """
180 if self.command_line: 177 if self.command_line:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 logging.info('Running: %s', command) 226 logging.info('Running: %s', command)
230 # Pass DIR_SOURCE_ROOT as the child's working directory so that relative 227 # Pass DIR_SOURCE_ROOT as the child's working directory so that relative
231 # paths in the arguments are resolved correctly. 228 # paths in the arguments are resolved correctly.
232 self.process = subprocess.Popen( 229 self.process = subprocess.Popen(
233 command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess, 230 command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess,
234 cwd=constants.DIR_SOURCE_ROOT) 231 cwd=constants.DIR_SOURCE_ROOT)
235 if self.process: 232 if self.process:
236 if self.pipe_out: 233 if self.pipe_out:
237 self.is_ready = self._WaitToStartAndGetPortFromTestServer() 234 self.is_ready = self._WaitToStartAndGetPortFromTestServer()
238 else: 235 else:
239 self.is_ready = _CheckPortStatus(self.host_port, True) 236 self.is_ready = _CheckPortNotAvailable(self.host_port)
240 if self.is_ready: 237 if self.is_ready:
241 Forwarder.Map([(0, self.host_port)], self.device, self.tool) 238 Forwarder.Map([(0, self.host_port)], self.device, self.tool)
242 # Check whether the forwarder is ready on the device. 239 # Check whether the forwarder is ready on the device.
243 self.is_ready = False 240 self.is_ready = False
244 device_port = Forwarder.DevicePortForHostPort(self.host_port) 241 device_port = Forwarder.DevicePortForHostPort(self.host_port)
245 if device_port and _CheckDevicePortStatus(self.device, device_port): 242 if device_port and _CheckDevicePortStatus(self.device, device_port):
246 self.is_ready = True 243 self.is_ready = True
247 self.forwarder_device_port = device_port 244 self.forwarder_device_port = device_port
248 # Wake up the request handler thread. 245 # Wake up the request handler thread.
249 self.ready_event.set() 246 self.ready_event.set()
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 def _KillTestServer(self): 336 def _KillTestServer(self):
340 """Stops the test server instance.""" 337 """Stops the test server instance."""
341 # There should only ever be one test server at a time. This may do the 338 # There should only ever be one test server at a time. This may do the
342 # wrong thing if we try and start multiple test servers. 339 # wrong thing if we try and start multiple test servers.
343 if not self.server.test_server_instance: 340 if not self.server.test_server_instance:
344 return 341 return
345 port = self.server.test_server_instance.host_port 342 port = self.server.test_server_instance.host_port
346 logging.info('Handling request to kill a test server on port: %d.', port) 343 logging.info('Handling request to kill a test server on port: %d.', port)
347 self.server.test_server_instance.Stop() 344 self.server.test_server_instance.Stop()
348 # Make sure the status of test server is correct before sending response. 345 # Make sure the status of test server is correct before sending response.
349 if _CheckPortStatus(port, False): 346 if _CheckPortAvailable(port):
350 self._SendResponse(200, 'OK', {}, 'killed') 347 self._SendResponse(200, 'OK', {}, 'killed')
351 logging.info('Test server on port %d is killed', port) 348 logging.info('Test server on port %d is killed', port)
352 else: 349 else:
353 self._SendResponse(500, 'Test Server Error.', {}, '') 350 self._SendResponse(500, 'Test Server Error.', {}, '')
354 logging.info('Encounter problem during killing a test server.') 351 logging.info('Encounter problem during killing a test server.')
355 self.server.test_server_instance = None 352 self.server.test_server_instance = None
356 353
357 def do_POST(self): 354 def do_POST(self):
358 parsed_path = urlparse.urlparse(self.path) 355 parsed_path = urlparse.urlparse(self.path)
359 action = parsed_path.path 356 action = parsed_path.path
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 413
417 def CleanupState(self): 414 def CleanupState(self):
418 """Cleans up the spawning server state. 415 """Cleans up the spawning server state.
419 416
420 This should be called if the test server spawner is reused, 417 This should be called if the test server spawner is reused,
421 to avoid sharing the test server instance. 418 to avoid sharing the test server instance.
422 """ 419 """
423 if self.server.test_server_instance: 420 if self.server.test_server_instance:
424 self.server.test_server_instance.Stop() 421 self.server.test_server_instance.Stop()
425 self.server.test_server_instance = None 422 self.server.test_server_instance = None
OLDNEW
« no previous file with comments | « no previous file | build/android/pylib/ports.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698