OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 try: |
| 7 import json |
| 8 except ImportError: # < 2.6 |
| 9 import simplejson as json |
| 10 |
| 11 import os |
| 12 import optparse |
| 13 import platform |
| 14 import subprocess |
| 15 import sys |
| 16 import time |
| 17 import unittest |
| 18 import urllib2 |
| 19 from urlparse import urlparse |
| 20 |
| 21 if sys.version_info[0] <= 2 and sys.version_info[1] < 6: |
| 22 # subprocess.Popen.kill is not available prior to 2.6. |
| 23 if platform.system() == 'Windows': |
| 24 import win32api |
| 25 else: |
| 26 import signal |
| 27 |
| 28 |
| 29 WEBDRIVER_EXE = os.path.abspath(os.path.join('.', 'chromedriver')) |
| 30 if platform.system() == 'Windows': |
| 31 WEBDRIVER_EXE = '%s.exe' % WEBDRIVER_EXE |
| 32 WEBDRIVER_PORT = 8080 |
| 33 WEBDRIVER_SERVER_URL = None |
| 34 WEBDRIVER_PROCESS = None |
| 35 |
| 36 |
| 37 def setUpModule(): |
| 38 """Starts the webdriver server, if necessary.""" |
| 39 global WEBDRIVER_SERVER_URL |
| 40 global WEBDRIVER_PROCESS |
| 41 if not WEBDRIVER_SERVER_URL: |
| 42 WEBDRIVER_SERVER_URL = 'http://localhost:%d' % WEBDRIVER_PORT |
| 43 WEBDRIVER_PROCESS = subprocess.Popen([WEBDRIVER_EXE, |
| 44 '--port=%d' % WEBDRIVER_PORT]) |
| 45 time.sleep(3) |
| 46 |
| 47 |
| 48 def tearDownModule(): |
| 49 """Kills the WebDriver server, if it was started for testing.""" |
| 50 global WEBDRIVER_PROCESS |
| 51 if WEBDRIVER_PROCESS: |
| 52 if sys.version_info[0] <= 2 and sys.version_info[1] < 6: |
| 53 # From http://stackoverflow.com/questions/1064335 |
| 54 if platform.system() == 'Windows': |
| 55 PROCESS_TERMINATE = 1 |
| 56 handle = win32api.OpenProcess(PROCESS_TERMINATE, False, |
| 57 WEBDRIVER_PROCESS.pid) |
| 58 win32api.TerminateProcess(handle, -1) |
| 59 win32api.CloseHandle(handle) |
| 60 else: |
| 61 os.kill(WEBDRIVER_PROCESS.pid, signal.SIGKILL) |
| 62 else: |
| 63 WEBDRIVER_PROCESS.kill() |
| 64 |
| 65 |
| 66 class Request(urllib2.Request): |
| 67 """Extends urllib2.Request to support all HTTP request types.""" |
| 68 |
| 69 def __init__(self, url, method=None, data=None): |
| 70 """Initialise a new HTTP request. |
| 71 |
| 72 Arguments: |
| 73 url: The full URL to send the request to. |
| 74 method: The HTTP request method to use; defaults to 'GET'. |
| 75 data: The data to send with the request as a string. Defaults to |
| 76 None and is ignored if |method| is not 'POST' or 'PUT'. |
| 77 """ |
| 78 if method is None: |
| 79 method = data is not None and 'POST' or 'GET' |
| 80 elif method not in ('POST', 'PUT'): |
| 81 data = None |
| 82 self.method = method |
| 83 urllib2.Request.__init__(self, url, data=data) |
| 84 |
| 85 def get_method(self): |
| 86 """Returns the HTTP method used by this request.""" |
| 87 return self.method |
| 88 |
| 89 |
| 90 def SendRequest(url, method=None, data=None): |
| 91 """Sends a HTTP request to the WebDriver server. |
| 92 |
| 93 Return values and exceptions raised are the same as those of |
| 94 |urllib2.urlopen|. |
| 95 |
| 96 Arguments: |
| 97 url: The full URL to send the request to. |
| 98 method: The HTTP request method to use; defaults to 'GET'. |
| 99 data: The data to send with the request as a string. Defaults to |
| 100 None and is ignored if |method| is not 'POST' or 'PUT'. |
| 101 |
| 102 Returns: |
| 103 A file-like object. |
| 104 """ |
| 105 request = Request(url, method=method, data=data) |
| 106 request.add_header('Accept', 'application/json') |
| 107 opener = urllib2.build_opener(urllib2.HTTPRedirectHandler()) |
| 108 return opener.open(request) |
| 109 |
| 110 |
| 111 class WebDriverSessionlessTest(unittest.TestCase): |
| 112 """Tests against the WebDriver REST protocol that do not require creating |
| 113 a session with the WebDriver server. |
| 114 """ |
| 115 |
| 116 def testShouldReturn404WhenSentAnUnknownCommandURL(self): |
| 117 request_url = '%s/foo' % WEBDRIVER_SERVER_URL |
| 118 try: |
| 119 SendRequest(request_url, method='GET') |
| 120 self.fail('Should have raised a urllib.HTTPError for returned 404') |
| 121 except urllib2.HTTPError, expected: |
| 122 self.assertEquals(404, expected.code) |
| 123 |
| 124 def testShouldReturnHTTP405WhenSendingANonPostToTheSessionURL(self): |
| 125 request_url = '%s/session' % WEBDRIVER_SERVER_URL |
| 126 try: |
| 127 SendRequest(request_url, method='GET') |
| 128 self.fail('Should have raised a urllib.HTTPError for returned 405') |
| 129 except urllib2.HTTPError, expected: |
| 130 self.assertEquals(405, expected.code) |
| 131 self.assertEquals('POST', expected.hdrs['Allow']) |
| 132 |
| 133 def testShouldGetA404WhenAttemptingToDeleteAnUnknownSession(self): |
| 134 request_url = '%s/session/unknown_session_id' % WEBDRIVER_SERVER_URL |
| 135 try: |
| 136 SendRequest(request_url, method='DELETE') |
| 137 self.fail('Should have raised a urllib.HTTPError for returned 404') |
| 138 except urllib2.HTTPError, expected: |
| 139 self.assertEquals(404, expected.code) |
| 140 |
| 141 |
| 142 class SessionTest(unittest.TestCase): |
| 143 """Tests requiring an active WebDriver session.""" |
| 144 |
| 145 def setUp(self): |
| 146 self.session_url = None |
| 147 |
| 148 def tearDown(self): |
| 149 if self.session_url: |
| 150 response = SendRequest(self.session_url, method='DELETE') |
| 151 try: |
| 152 self.assertEquals(200, response.code) |
| 153 finally: |
| 154 response.close() |
| 155 |
| 156 def testShouldBeGivenCapabilitiesWhenStartingASession(self): |
| 157 request_url = '%s/session' % WEBDRIVER_SERVER_URL |
| 158 response = SendRequest(request_url, method='POST', data='{}') |
| 159 try: |
| 160 self.assertEquals(200, response.code) |
| 161 self.session_url = response.geturl() # TODO(jleyba): verify this URL? |
| 162 |
| 163 data = json.loads(response.read()) |
| 164 self.assertTrue(isinstance(data, dict)) |
| 165 self.assertEquals(0, data['status']) |
| 166 |
| 167 url_parts = urlparse(self.session_url)[2].split('/') |
| 168 self.assertEquals(3, len(url_parts)) |
| 169 self.assertEquals('', url_parts[0]) |
| 170 self.assertEquals('session', url_parts[1]) |
| 171 self.assertEquals(data['sessionId'], url_parts[2]) |
| 172 |
| 173 capabilities = data['value'] |
| 174 self.assertTrue(isinstance(capabilities, dict)) |
| 175 |
| 176 self.assertEquals('chrome', capabilities['browserName']) |
| 177 self.assertTrue(capabilities['javascriptEnabled']) |
| 178 |
| 179 # Value depends on what version the server is starting. |
| 180 self.assertTrue('version' in capabilities) |
| 181 self.assertTrue( |
| 182 isinstance(capabilities['version'], unicode), |
| 183 'Expected a %s, but was %s' % (unicode, |
| 184 type(capabilities['version']))) |
| 185 |
| 186 system = platform.system() |
| 187 if system == 'Linux': |
| 188 self.assertEquals('linux', capabilities['platform'].lower()) |
| 189 elif system == 'Windows': |
| 190 self.assertEquals('windows', capabilities['platform'].lower()) |
| 191 elif system == 'Darwin': |
| 192 self.assertEquals('mac', capabilities['platform'].lower()) |
| 193 else: |
| 194 # No python on ChromeOS, so we won't have a platform value, but |
| 195 # the server will know and return the value accordingly. |
| 196 self.assertEquals('chromeos', capabilities['platform'].lower()) |
| 197 finally: |
| 198 response.close() |
| 199 |
| 200 |
| 201 if __name__ == '__main__': |
| 202 parser = optparse.OptionParser('%prog [options]') |
| 203 parser.add_option('-u', '--url', dest='url', action='store', |
| 204 type='string', default=None, |
| 205 help=('Specifies the URL of a remote WebDriver server to ' |
| 206 'test against. If not specified, a server will be ' |
| 207 'started on localhost according to the --exe and ' |
| 208 '--port flags')) |
| 209 parser.add_option('-e', '--exe', dest='exe', action='store', |
| 210 type='string', default=None, |
| 211 help=('Path to the WebDriver server executable that should ' |
| 212 'be started for testing; This flag is ignored if ' |
| 213 '--url is provided for a remote server.')) |
| 214 parser.add_option('-p', '--port', dest='port', action='store', |
| 215 type='int', default=8080, |
| 216 help=('The port to start the WebDriver server executable ' |
| 217 'on; This flag is ignored if --url is provided for a ' |
| 218 'remote server.')) |
| 219 |
| 220 (options, args) = parser.parse_args() |
| 221 # Strip out our flags so unittest.main() correct parses the remaining |
| 222 sys.argv = sys.argv[:1] |
| 223 sys.argv.extend(args) |
| 224 |
| 225 if options.url: |
| 226 WEBDRIVER_SERVER_URL = options.url |
| 227 else: |
| 228 if options.port: |
| 229 WEBDRIVER_PORT = options.port |
| 230 if options.exe: |
| 231 WEBDRIVER_EXE = options.exe |
| 232 if not os.path.exists(WEBDRIVER_EXE): |
| 233 parser.error('WebDriver server executable not found:\n\t%s\n' |
| 234 'Please specify a valid path with the --exe flag.' |
| 235 % WEBDRIVER_EXE) |
| 236 |
| 237 setUpModule() |
| 238 try: |
| 239 unittest.main() |
| 240 finally: |
| 241 tearDownModule() |
OLD | NEW |