1 # Copyright (c) 2011 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 """Represents a running ChromeDriver server.""" 6 7 import logging 8 import os 9 import platform 10 import signal 11 import subprocess 12 import sys 13 import threading 14 import time 15 import urllib2 16 17 18 class ChromeDriverServer: 19 """A running ChromeDriver server.""" 20 21 def __init__(self, process, port, url_base=None): 22 """Waits for the ChromeDriver server to fully start. 23 24 Args: 25 process: the server process 26 port: port that ChromeDriver is listening on 27 url_base: url base for receiving webdriver commands 28 Raises: 29 RuntimeError if ChromeDriver does not start 30 """ 31 self._process = process 32 self._port = port 33 self._url_base = url_base 34 maxTime = time.time() + 30 35 while time.time() < maxTime and not self.IsRunning(): 36 time.sleep(0.2) 37 if not self.IsRunning(): 38 raise RuntimeError('ChromeDriver server did not start') 39 40 def IsRunning(self): 41 """Returns whether the server is up and running.""" 42 try: 43 urllib2.urlopen(self.GetUrl() + '/status') 44 return True 45 except urllib2.URLError: 46 return False 47 48 def Kill(self): 49 """Kills the ChromeDriver server, if it is running.""" 50 def _WaitForShutdown(process, shutdown_event): 51 """Waits for the process to quit and then notifies.""" 52 process.wait() 53 shutdown_event.acquire() 54 shutdown_event.notify() 55 shutdown_event.release() 56 57 if self._process is None: 58 return 59 try: 60 urllib2.urlopen(self.GetUrl() + '/shutdown').close() 61 except urllib2.URLError: 62 # Could not shutdown. Kill. 63 pid = self._process.pid 64 if platform.system() == 'Windows': 65 subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)]) 66 else: 67 os.kill(pid, signal.SIGTERM) 68 69 # Wait for ChromeDriver process to exit before returning. 70 # Even if we had to kill the process above, we still should call wait 71 # to cleanup the zombie. 72 shutdown_event = threading.Condition() 73 shutdown_event.acquire() 74 wait_thread = threading.Thread( 75 target=_WaitForShutdown, 76 args=(self._process, shutdown_event)) 77 wait_thread.start() 78 shutdown_event.wait(10) 79 shutdown_event.release() 80 self._process = None 81 82 def GetUrl(self): 83 url = 'http://localhost:' + str(self._port) 84 if self._url_base: 85 url += self._url_base 86 return url 87 88 def GetPort(self): 89 return self._port 90