blob: 00c98915d9d016815388b8bd2755d78aca5f81aa [file] [log] [blame]
Dan Shic1d263b2013-10-04 17:31:38 -07001# Copyright (c) 2013 The Chromium OS 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
5import atexit
6import logging
7import os
8import urllib2
9
10from selenium import webdriver
11
12import common
13from autotest_lib.client.bin import utils
14from autotest_lib.client.common_lib.cros import chrome
15
16CHROMEDRIVER_EXE_PATH = '/usr/local/chromedriver/chromedriver'
17
18class chromedriver(object):
19 """Wrapper class, a context manager type, for tests to use Chrome Driver."""
20
21 def __init__(self, extra_chrome_flags=[], subtract_extra_chrome_flags=[],
22 *args, **kwargs):
23 """Initialize.
24
25 @param extra_chrome_flags: Extra chrome flags to pass to chrome, if any.
26 @param subtract_extra_chrome_flags: Remove default flags passed to
27 chrome by chromedriver, if any.
28 """
29 assert os.geteuid() == 0, 'Need superuser privileges'
30
31 # Log in with telemetry
32 self._browser = chrome.Chrome().browser
33
34 # Start ChromeDriver server
35 self._server = chromedriver_server(CHROMEDRIVER_EXE_PATH)
36
37 chromeOptions = {'debuggerAddress':
38 ('localhost:%d' %
39 utils.get_chrome_remote_debugging_port())}
40 capabilities = {'chromeOptions':chromeOptions}
41 # Handle to chromedriver, for chrome automation.
42 self.driver = webdriver.Remote(command_executor=self._server.url,
43 desired_capabilities=capabilities)
44
45
46 def __enter__(self):
47 return self
48
49
50 def __exit__(self, *args):
51 """Clean up after running the test.
52
53 """
54 if hasattr(self, 'driver') and self.driver:
55 self.driver.close()
56 del self.driver
57
58 if hasattr(self, '_server') and self._server:
59 self._server.close()
60 del self._server
61
62 if hasattr(self, '_browser') and self._browser:
63 self._browser.Close()
64 del self._browser
65
66
67class chromedriver_server(object):
68 """A running ChromeDriver server.
69
70 This code is migrated from chrome:
71 src/chrome/test/chromedriver/server/server.py
72 """
73
74 def __init__(self, exe_path):
75 """Starts the ChromeDriver server and waits for it to be ready.
76
77 Args:
78 exe_path: path to the ChromeDriver executable
79 Raises:
80 RuntimeError if ChromeDriver fails to start
81 """
82 if not os.path.exists(exe_path):
83 raise RuntimeError('ChromeDriver exe not found at: ' + exe_path)
84
85 port = utils.get_unused_port()
86 chromedriver_args = [exe_path, '--port=%d' % port]
87 self.bg_job = utils.BgJob(chromedriver_args, stderr_level=logging.DEBUG)
88 self.url = 'http://localhost:%d' % port
89 if self.bg_job is None:
90 raise RuntimeError('ChromeDriver server cannot be started')
91
92 try:
93 timeout_msg = 'Timeout on waiting for ChromeDriver to start.'
94 utils.poll_for_condition(self.is_running,
95 exception=utils.TimeoutError(timeout_msg),
96 timeout=10,
97 sleep_interval=.1)
98 except utils.TimeoutError:
99 self.close_bgjob()
100 raise RuntimeError('ChromeDriver server did not start')
101
102 logging.debug('Chrome Driver server is up and listening at port %d.',
103 port)
104 atexit.register(self.close)
105
106
107 def is_running(self):
108 """Returns whether the server is up and running."""
109 try:
110 urllib2.urlopen(self.url + '/status')
111 return True
112 except urllib2.URLError as e:
113 return False
114
115
116 def close_bgjob(self):
117 """Close background job and log stdout and stderr."""
118 utils.nuke_subprocess(self.bg_job.sp)
119 utils.join_bg_jobs([self.bg_job], timeout=1)
120 result = self.bg_job.result
121 if result.stdout or result.stderr:
122 logging.info('stdout of Chrome Driver:\n%s', result.stdout)
123 logging.error('stderr of Chrome Driver:\n%s', result.stderr)
124
125
126 def close(self):
127 """Kills the ChromeDriver server, if it is running."""
128 if self.bg_job is None:
129 return
130
131 try:
132 urllib2.urlopen(self.url + '/shutdown', timeout=10).close()
133 except:
134 pass
135
136 self.close_bgjob()