Home | History | Annotate | Download | only in test
      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