diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-04 16:48:26 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-04 16:48:26 +0000 |
commit | 9650ea1b907196736da51be053992c50152d0882 (patch) | |
tree | 953602199162d3ac9120c816e888a820c839dc83 | |
parent | 39be34adcfe428dd7a0ad132b23796d9be24a7fd (diff) | |
download | chromium_src-9650ea1b907196736da51be053992c50152d0882.zip chromium_src-9650ea1b907196736da51be053992c50152d0882.tar.gz chromium_src-9650ea1b907196736da51be053992c50152d0882.tar.bz2 |
Add method for shutting down ChromeDriver gracefully.
Merge webdriver_tests into chromedriver_tests.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6368068
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73809 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/webdriver/chromedriver_launcher.py | 146 | ||||
-rwxr-xr-x | chrome/test/webdriver/chromedriver_tests.py | 163 | ||||
-rw-r--r-- | chrome/test/webdriver/server.cc | 84 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_tests.py | 241 | ||||
-rw-r--r-- | third_party/mongoose/README.chromium | 3 | ||||
-rw-r--r-- | third_party/mongoose/mongoose.c | 7 |
6 files changed, 344 insertions, 300 deletions
diff --git a/chrome/test/webdriver/chromedriver_launcher.py b/chrome/test/webdriver/chromedriver_launcher.py index 1777525..fb6d35b 100644 --- a/chrome/test/webdriver/chromedriver_launcher.py +++ b/chrome/test/webdriver/chromedriver_launcher.py @@ -12,15 +12,11 @@ For ChromeDriver documentation, refer to: import logging import os import platform +import signal import subprocess import sys - -if sys.version_info < (2,6): - # Subprocess.Popen.kill is not available prior to 2.6. - if platform.system() == 'Windows': - import win32api - else: - import signal +import threading +import urllib2 class ChromeDriverLauncher: @@ -39,35 +35,31 @@ class ChromeDriverLauncher: self._port = port if self._exe_path is None: self._exe_path = ChromeDriverLauncher.LocateExe() + if self._exe_path is None: + raise RuntimeError('ChromeDriver exe could not be found in its default ' + 'location. Searched in following directories: ' + + ', '.join(self.DefaultExeLocations())) if self._root_path is None: self._root_path = '.' - if self._port is None: - self._port = 9515 self._root_path = os.path.abspath(self._root_path) self._process = None if not os.path.exists(self._exe_path): raise RuntimeError('ChromeDriver exe not found at: ' + self._exe_path) + + os.environ['PATH'] = os.path.dirname(self._exe_path) + os.environ['PATH'] self.Start() @staticmethod - def LocateExe(): - """Attempts to locate the ChromeDriver executable. - - This searches the current directory, then checks the appropriate build - locations according to platform. + def DefaultExeLocations(): + """Returns the paths that are used to find the ChromeDriver executable. Returns: - absolute path to the ChromeDriver executable, or None if not found + a list of directories that would be searched for the executable """ - exe_name = 'chromedriver' - if platform.system() == 'Windows': - exe_name += '.exe' - if os.path.exists(exe_name): - return os.path.abspath(exe_name) - script_dir = os.path.dirname(__file__) - chrome_src = os.path.join(script_dir, os.pardir, os.pardir, os.pardir) + chrome_src = os.path.abspath(os.path.join( + script_dir, os.pardir, os.pardir, os.pardir)) bin_dirs = { 'linux2': [ os.path.join(chrome_src, 'out', 'Debug'), os.path.join(chrome_src, 'sconsbuild', 'Debug'), @@ -80,7 +72,23 @@ class ChromeDriverLauncher: os.path.join(chrome_src, 'chrome', 'Release'), os.path.join(chrome_src, 'build', 'Release')], } - for dir in bin_dirs.get(sys.platform, []): + return [os.getcwd()] + bin_dirs.get(sys.platform, []) + + @staticmethod + def LocateExe(): + """Attempts to locate the ChromeDriver executable. + + This searches the current directory, then checks the appropriate build + locations according to platform. + + Returns: + absolute path to the ChromeDriver executable, or None if not found + """ + exe_name = 'chromedriver' + if platform.system() == 'Windows': + exe_name += '.exe' + + for dir in ChromeDriverLauncher.DefaultExeLocations(): path = os.path.join(dir, exe_name) if os.path.exists(path): return os.path.abspath(path) @@ -90,38 +98,96 @@ class ChromeDriverLauncher: """Starts a new ChromeDriver process. Kills a previous one if it is still running. + + Raises: + RuntimeError if ChromeDriver does not start """ + def _WaitForLaunchResult(stdout, started_event, launch_result): + """Reads from the stdout of ChromeDriver and parses the launch result. + + Args: + stdout: handle to ChromeDriver's standard output + started_event: condition variable to notify when the launch result + has been parsed + launch_result: dictionary to add the result of this launch to + """ + status_line = stdout.readline() + started_event.acquire() + try: + launch_result['success'] = status_line.startswith('Started') + launch_result['status_line'] = status_line + if launch_result['success']: + port_line = stdout.readline() + launch_result['port'] = int(port_line.split('=')[1]) + started_event.notify() + finally: + started_event.release() + if self._process is not None: self.Kill() - proc = subprocess.Popen([self._exe_path, - '--port=%d' % self._port, - '--root="%s"' % self._root_path]) + + chromedriver_args = [self._exe_path, '--root=%s' % self._root_path] + if self._port is not None: + chromedriver_args += ['--port=%d' % self._port] + proc = subprocess.Popen(chromedriver_args, + stdout=subprocess.PIPE) if proc is None: raise RuntimeError('ChromeDriver cannot be started') - logging.info('Started chromedriver at port %s' % self._port) self._process = proc + # Wait for ChromeDriver to be initialized before returning. + launch_result = {} + started_event = threading.Condition() + started_event.acquire() + spawn_thread = threading.Thread( + target=_WaitForLaunchResult, + args=(proc.stdout, started_event, launch_result)) + spawn_thread.start() + started_event.wait(20) + timed_out = 'success' not in launch_result + started_event.release() + if timed_out: + raise RuntimeError('ChromeDriver did not respond') + elif not launch_result['success']: + raise RuntimeError('ChromeDriver failed to launch: ' + + launch_result['status_line']) + self._port = launch_result['port'] + logging.info('ChromeDriver running on port %s' % self._port) + def Kill(self): """Kills a currently running ChromeDriver process, if it is running.""" + def _WaitForShutdown(process, shutdown_event): + """Waits for the process to quit and then notifies.""" + process.wait() + shutdown_event.acquire() + shutdown_event.notify() + shutdown_event.release() + if self._process is None: return - if sys.version_info < (2,6): - # From http://stackoverflow.com/questions/1064335 + try: + urllib2.urlopen(self.GetURL() + '/shutdown').close() + except urllib2.URLError: + # Could not shutdown. Kill. + pid = self._process.pid if platform.system() == 'Windows': - PROCESS_TERMINATE = 1 - handle = win32api.OpenProcess(PROCESS_TERMINATE, False, - self._process.pid) - win32api.TerminateProcess(handle, -1) - win32api.CloseHandle(handle) + subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)]) else: - os.kill(self._process.pid, signal.SIGKILL) - else: - self._process.kill() + os.kill(pid, signal.SIGTERM) + + # Wait for ChromeDriver process to exit before returning. + # Even if we had to kill the process above, we still should call wait + # to cleanup the zombie. + shutdown_event = threading.Condition() + shutdown_event.acquire() + wait_thread = threading.Thread( + target=_WaitForShutdown, + args=(self._process, shutdown_event)) + wait_thread.start() + shutdown_event.wait(10) + shutdown_event.release() self._process = None - def __del__(self): - self.Kill() - def GetURL(self): return 'http://localhost:' + str(self._port) diff --git a/chrome/test/webdriver/chromedriver_tests.py b/chrome/test/webdriver/chromedriver_tests.py index 2e99b14..0dd0ecf 100755 --- a/chrome/test/webdriver/chromedriver_tests.py +++ b/chrome/test/webdriver/chromedriver_tests.py @@ -10,9 +10,13 @@ If your test is testing a specific part of the WebDriver API, consider adding it to the appropriate place in the WebDriver tree instead. """ +import platform import os +import simplejson as json import sys import unittest +import urllib2 +import urlparse from chromedriver_launcher import ChromeDriverLauncher import chromedriver_paths @@ -23,14 +27,171 @@ sys.path += [chromedriver_paths.PYTHON_BINDINGS] from selenium.webdriver.remote.webdriver import WebDriver -class ChromeDriverTest(unittest.TestCase): +class Request(urllib2.Request): + """Extends urllib2.Request to support all HTTP request types.""" + + def __init__(self, url, method=None, data=None): + """Initialise a new HTTP request. + + Arguments: + url: The full URL to send the request to. + method: The HTTP request method to use; defaults to 'GET'. + data: The data to send with the request as a string. Defaults to + None and is ignored if |method| is not 'POST' or 'PUT'. + """ + if method is None: + method = data is not None and 'POST' or 'GET' + elif method not in ('POST', 'PUT'): + data = None + self.method = method + urllib2.Request.__init__(self, url, data=data) + + def get_method(self): + """Returns the HTTP method used by this request.""" + return self.method + + +def SendRequest(url, method=None, data=None): + """Sends a HTTP request to the WebDriver server. + + Return values and exceptions raised are the same as those of + |urllib2.urlopen|. + + Arguments: + url: The full URL to send the request to. + method: The HTTP request method to use; defaults to 'GET'. + data: The data to send with the request as a string. Defaults to + None and is ignored if |method| is not 'POST' or 'PUT'. + + Returns: + A file-like object. + """ + request = Request(url, method=method, data=data) + request.add_header('Accept', 'application/json') + opener = urllib2.build_opener(urllib2.HTTPRedirectHandler()) + return opener.open(request) + + +class BasicTest(unittest.TestCase): + """Basic ChromeDriver tests.""" + def setUp(self): self._launcher = ChromeDriverLauncher() + def tearDown(self): + self._launcher.Kill() + + def testShouldReturn404WhenSentAnUnknownCommandURL(self): + request_url = self._launcher.GetURL() + '/foo' + try: + SendRequest(request_url, method='GET') + self.fail('Should have raised a urllib.HTTPError for returned 404') + except urllib2.HTTPError, expected: + self.assertEquals(404, expected.code) + + def testShouldReturnHTTP405WhenSendingANonPostToTheSessionURL(self): + request_url = self._launcher.GetURL() + '/session' + try: + SendRequest(request_url, method='GET') + self.fail('Should have raised a urllib.HTTPError for returned 405') + except urllib2.HTTPError, expected: + self.assertEquals(405, expected.code) + self.assertEquals('POST', expected.hdrs['Allow']) + + def testShouldGetA404WhenAttemptingToDeleteAnUnknownSession(self): + request_url = self._launcher.GetURL() + '/session/unkown_session_id' + try: + SendRequest(request_url, method='DELETE') + self.fail('Should have raised a urllib.HTTPError for returned 404') + except urllib2.HTTPError, expected: + self.assertEquals(404, expected.code) + + def testCanStartChromeDriverOnSpecificPort(self): + launcher = ChromeDriverLauncher(port=9520) + self.assertEquals(9520, launcher.GetPort()) + driver = WebDriver(launcher.GetURL(), 'chrome', 'any') + driver.quit() + + +class SessionTest(unittest.TestCase): + """Tests dealing with WebDriver sessions.""" + + def setUp(self): + self._launcher = ChromeDriverLauncher() + + def tearDown(self): + self._launcher.Kill() + + def testCreatingSessionShouldRedirectToCorrectURL(self): + request_url = self._launcher.GetURL() + '/session' + response = SendRequest(request_url, method='POST', data='{}') + self.assertEquals(200, response.code) + self.session_url = response.geturl() # TODO(jleyba): verify this URL? + + data = json.loads(response.read()) + self.assertTrue(isinstance(data, dict)) + self.assertEquals(0, data['status']) + + url_parts = urlparse.urlparse(self.session_url)[2].split('/') + self.assertEquals(3, len(url_parts)) + self.assertEquals('', url_parts[0]) + self.assertEquals('session', url_parts[1]) + self.assertEquals(data['sessionId'], url_parts[2]) + + def testShouldBeGivenCapabilitiesWhenStartingASession(self): + driver = WebDriver(self._launcher.GetURL(), 'chrome', 'any') + capabilities = driver.capabilities + + self.assertEquals('chrome', capabilities['browserName']) + self.assertTrue(capabilities['javascriptEnabled']) + + # Value depends on what version the server is starting. + self.assertTrue('version' in capabilities) + self.assertTrue( + isinstance(capabilities['version'], unicode), + 'Expected a %s, but was %s' % (unicode, + type(capabilities['version']))) + + system = platform.system() + if system == 'Linux': + self.assertEquals('linux', capabilities['platform'].lower()) + elif system == 'Windows': + self.assertEquals('windows', capabilities['platform'].lower()) + elif system == 'Darwin': + self.assertEquals('mac', capabilities['platform'].lower()) + else: + # No python on ChromeOS, so we won't have a platform value, but + # the server will know and return the value accordingly. + self.assertEquals('chromeos', capabilities['platform'].lower()) + driver.quit() + def testSessionCreationDeletion(self): driver = WebDriver(self._launcher.GetURL(), 'chrome', 'any') driver.quit() + def testMultipleSessionCreationDeletion(self): + for i in range(10): + driver = WebDriver(self._launcher.GetURL(), 'chrome', 'any') + driver.quit() + + def testSessionCommandsAfterSessionDeletionReturn404(self): + driver = WebDriver(self._launcher.GetURL(), 'chrome', 'any') + session_id = driver.session_id + driver.quit() + try: + response = SendRequest(self._launcher.GetURL() + '/session/' + session_id, + method='GET') + self.fail('Should have thrown 404 exception') + except urllib2.HTTPError, expected: + self.assertEquals(404, expected.code) + + def testMultipleConcurrentSessions(self): + drivers = [] + for i in range(10): + drivers += [WebDriver(self._launcher.GetURL(), 'chrome', 'any')] + for driver in drivers: + driver.quit() + if __name__ == '__main__': unittest.main(module='chromedriver_tests', diff --git a/chrome/test/webdriver/server.cc b/chrome/test/webdriver/server.cc index 6409524..2994477 100644 --- a/chrome/test/webdriver/server.cc +++ b/chrome/test/webdriver/server.cc @@ -17,11 +17,15 @@ #include "base/at_exit.h" #include "base/command_line.h" #include "base/logging.h" +#include "base/string_number_conversions.h" #include "base/scoped_ptr.h" +#include "base/string_split.h" #include "base/string_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" #include "base/utf_string_conversions.h" - +#include "chrome/common/chrome_paths.h" #include "chrome/test/webdriver/dispatch.h" #include "chrome/test/webdriver/session_manager.h" #include "chrome/test/webdriver/utility_functions.h" @@ -55,12 +59,25 @@ signal_handler(int sig_num) { } namespace webdriver { + +void Shutdown(struct mg_connection* connection, + const struct mg_request_info* request_info, + void* user_data) { + base::WaitableEvent* shutdown_event = + reinterpret_cast<base::WaitableEvent*>(user_data); + mg_printf(connection, "HTTP/1.1 200 OK\r\n\r\n"); + shutdown_event->Signal(); +} + template <typename CommandType> void SetCallback(struct mg_context* ctx, const char* pattern) { mg_set_uri_callback(ctx, pattern, &Dispatch<CommandType>, NULL); } -void InitCallbacks(struct mg_context* ctx) { +void InitCallbacks(struct mg_context* ctx, + base::WaitableEvent* shutdown_event) { + mg_set_uri_callback(ctx, "/shutdown", &Shutdown, shutdown_event); + SetCallback<CreateSession>(ctx, "/session"); SetCallback<BackCommand>(ctx, "/session/*/back"); SetCallback<ExecuteCommand>(ctx, "/session/*/execute"); @@ -72,7 +89,7 @@ void InitCallbacks(struct mg_context* ctx) { SetCallback<SpeedCommand>(ctx, "/session/*/speed"); // WebElement commands - SetCallback<ImplicitWaitCommand>(ctx, "/session/*/timeouts/implicit_wait"); + SetCallback<ImplicitWaitCommand>(ctx, "/session/*/timeouts/implicit_wait"); SetCallback<FindOneElementCommand>(ctx, "/session/*/element"); SetCallback<FindManyElementsCommand>(ctx, "/session/*/elements"); SetCallback<FindOneElementCommand>(ctx, "/session/*/element/*/element"); @@ -84,13 +101,32 @@ void InitCallbacks(struct mg_context* ctx) { } } // namespace webdriver +// Configures mongoose according to the given command line flags. +// Returns true on success. +bool SetMongooseOptions(struct mg_context* ctx, + const std::string& port, + const std::string& root) { + if (!mg_set_option(ctx, "ports", port.c_str())) { + std::cout << "ChromeDriver cannot bind to port (" + << port.c_str() << ")" << std::endl; + return false; + } + if (root.length()) + mg_set_option(ctx, "root", root.c_str()); + // Lower the default idle time to 1 second. Idle time refers to how long a + // worker thread will wait for new connections before exiting. + // This is so mongoose quits in a reasonable amount of time. + mg_set_option(ctx, "idle_time", "1"); + return true; +} + // Sets up and runs the Mongoose HTTP server for the JSON over HTTP // protcol of webdriver. The spec is located at: // http://code.google.com/p/selenium/wiki/JsonWireProtocol. int main(int argc, char *argv[]) { struct mg_context *ctx; base::AtExitManager exit; - std::string port = "9515"; + base::WaitableEvent shutdown_event(false, false); #ifdef OS_POSIX CommandLine cmd_line = CommandLine(argc, argv); #elif OS_WIN @@ -111,9 +147,20 @@ int main(int argc, char *argv[]) { #endif srand((unsigned int)time(NULL)); - if (cmd_line.HasSwitch(std::string("port"))) { - port = cmd_line.GetSwitchValueASCII(std::string("port")); - } + // Register Chrome's path provider so that the AutomationProxy will find our + // built Chrome. + chrome::RegisterPathProvider(); + TestTimeouts::Initialize(); + + // Parse command line flags. + std::string port = "9515"; + std::string root; + if (cmd_line.HasSwitch("port")) + port = cmd_line.GetSwitchValueASCII("port"); + // By default, mongoose serves files from the current working directory. The + // 'root' flag allows the user to specify a different location to serve from. + if (cmd_line.HasSwitch("root")) + root = cmd_line.GetSwitchValueASCII("root"); VLOG(1) << "Using port: " << port; webdriver::SessionManager* session = webdriver::SessionManager::GetInstance(); @@ -123,14 +170,24 @@ int main(int argc, char *argv[]) { // Listen on port 9515 or port specified on command line. // TODO(jmikhail) Maybe add port 9516 as a secure connection. ctx = mg_start(); - mg_set_option(ctx, "ports", port.c_str()); + if (!SetMongooseOptions(ctx, port, root)) { + mg_stop(ctx); + return 1; + } - webdriver::InitCallbacks(ctx); + webdriver::InitCallbacks(ctx, &shutdown_event); - std::cout << "Starting server on port: " << port << std::endl; - // The default behavior is to run this service forever. - while (true) - base::PlatformThread::Sleep(3600); + // The tests depend on parsing the first line ChromeDriver outputs, + // so all other logging should happen after this. + std::cout << "Started ChromeDriver" << std::endl + << "port=" << port << std::endl; + + if (root.length()) { + VLOG(1) << "Serving files from the current working directory"; + } + + // Run until we receive command to shutdown. + shutdown_event.Wait(); // We should not reach here since the service should never quit. // TODO(jmikhail): register a listener for SIGTERM and break the @@ -138,4 +195,3 @@ int main(int argc, char *argv[]) { mg_stop(ctx); return (EXIT_SUCCESS); } - diff --git a/chrome/test/webdriver/webdriver_tests.py b/chrome/test/webdriver/webdriver_tests.py deleted file mode 100644 index 2d95871..0000000 --- a/chrome/test/webdriver/webdriver_tests.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -try: - import json -except ImportError: # < 2.6 - import simplejson as json - -import os -import optparse -import platform -import subprocess -import sys -import time -import unittest -import urllib2 -from urlparse import urlparse - -if sys.version_info[0] <= 2 and sys.version_info[1] < 6: - # subprocess.Popen.kill is not available prior to 2.6. - if platform.system() == 'Windows': - import win32api - else: - import signal - - -WEBDRIVER_EXE = os.path.abspath(os.path.join('.', 'chromedriver')) -if platform.system() == 'Windows': - WEBDRIVER_EXE = '%s.exe' % WEBDRIVER_EXE -WEBDRIVER_PORT = 8080 -WEBDRIVER_SERVER_URL = None -WEBDRIVER_PROCESS = None - - -def setUpModule(): - """Starts the webdriver server, if necessary.""" - global WEBDRIVER_SERVER_URL - global WEBDRIVER_PROCESS - if not WEBDRIVER_SERVER_URL: - WEBDRIVER_SERVER_URL = 'http://localhost:%d' % WEBDRIVER_PORT - WEBDRIVER_PROCESS = subprocess.Popen([WEBDRIVER_EXE, - '--port=%d' % WEBDRIVER_PORT]) - time.sleep(3) - - -def tearDownModule(): - """Kills the WebDriver server, if it was started for testing.""" - global WEBDRIVER_PROCESS - if WEBDRIVER_PROCESS: - if sys.version_info[0] <= 2 and sys.version_info[1] < 6: - # From http://stackoverflow.com/questions/1064335 - if platform.system() == 'Windows': - PROCESS_TERMINATE = 1 - handle = win32api.OpenProcess(PROCESS_TERMINATE, False, - WEBDRIVER_PROCESS.pid) - win32api.TerminateProcess(handle, -1) - win32api.CloseHandle(handle) - else: - os.kill(WEBDRIVER_PROCESS.pid, signal.SIGKILL) - else: - WEBDRIVER_PROCESS.kill() - - -class Request(urllib2.Request): - """Extends urllib2.Request to support all HTTP request types.""" - - def __init__(self, url, method=None, data=None): - """Initialise a new HTTP request. - - Arguments: - url: The full URL to send the request to. - method: The HTTP request method to use; defaults to 'GET'. - data: The data to send with the request as a string. Defaults to - None and is ignored if |method| is not 'POST' or 'PUT'. - """ - if method is None: - method = data is not None and 'POST' or 'GET' - elif method not in ('POST', 'PUT'): - data = None - self.method = method - urllib2.Request.__init__(self, url, data=data) - - def get_method(self): - """Returns the HTTP method used by this request.""" - return self.method - - -def SendRequest(url, method=None, data=None): - """Sends a HTTP request to the WebDriver server. - - Return values and exceptions raised are the same as those of - |urllib2.urlopen|. - - Arguments: - url: The full URL to send the request to. - method: The HTTP request method to use; defaults to 'GET'. - data: The data to send with the request as a string. Defaults to - None and is ignored if |method| is not 'POST' or 'PUT'. - - Returns: - A file-like object. - """ - request = Request(url, method=method, data=data) - request.add_header('Accept', 'application/json') - opener = urllib2.build_opener(urllib2.HTTPRedirectHandler()) - return opener.open(request) - - -class WebDriverSessionlessTest(unittest.TestCase): - """Tests against the WebDriver REST protocol that do not require creating - a session with the WebDriver server. - """ - - def testShouldReturn404WhenSentAnUnknownCommandURL(self): - request_url = '%s/foo' % WEBDRIVER_SERVER_URL - try: - SendRequest(request_url, method='GET') - self.fail('Should have raised a urllib.HTTPError for returned 404') - except urllib2.HTTPError, expected: - self.assertEquals(404, expected.code) - - def testShouldReturnHTTP405WhenSendingANonPostToTheSessionURL(self): - request_url = '%s/session' % WEBDRIVER_SERVER_URL - try: - SendRequest(request_url, method='GET') - self.fail('Should have raised a urllib.HTTPError for returned 405') - except urllib2.HTTPError, expected: - self.assertEquals(405, expected.code) - self.assertEquals('POST', expected.hdrs['Allow']) - - def testShouldGetA404WhenAttemptingToDeleteAnUnknownSession(self): - request_url = '%s/session/unknown_session_id' % WEBDRIVER_SERVER_URL - try: - SendRequest(request_url, method='DELETE') - self.fail('Should have raised a urllib.HTTPError for returned 404') - except urllib2.HTTPError, expected: - self.assertEquals(404, expected.code) - - -class SessionTest(unittest.TestCase): - """Tests requiring an active WebDriver session.""" - - def setUp(self): - self.session_url = None - - def tearDown(self): - if self.session_url: - response = SendRequest(self.session_url, method='DELETE') - try: - self.assertEquals(200, response.code) - finally: - response.close() - - def testShouldBeGivenCapabilitiesWhenStartingASession(self): - request_url = '%s/session' % WEBDRIVER_SERVER_URL - response = SendRequest(request_url, method='POST', data='{}') - try: - self.assertEquals(200, response.code) - self.session_url = response.geturl() # TODO(jleyba): verify this URL? - - data = json.loads(response.read()) - self.assertTrue(isinstance(data, dict)) - self.assertEquals(0, data['status']) - - url_parts = urlparse(self.session_url)[2].split('/') - self.assertEquals(3, len(url_parts)) - self.assertEquals('', url_parts[0]) - self.assertEquals('session', url_parts[1]) - self.assertEquals(data['sessionId'], url_parts[2]) - - capabilities = data['value'] - self.assertTrue(isinstance(capabilities, dict)) - - self.assertEquals('chrome', capabilities['browserName']) - self.assertTrue(capabilities['javascriptEnabled']) - - # Value depends on what version the server is starting. - self.assertTrue('version' in capabilities) - self.assertTrue( - isinstance(capabilities['version'], unicode), - 'Expected a %s, but was %s' % (unicode, - type(capabilities['version']))) - - system = platform.system() - if system == 'Linux': - self.assertEquals('linux', capabilities['platform'].lower()) - elif system == 'Windows': - self.assertEquals('windows', capabilities['platform'].lower()) - elif system == 'Darwin': - self.assertEquals('mac', capabilities['platform'].lower()) - else: - # No python on ChromeOS, so we won't have a platform value, but - # the server will know and return the value accordingly. - self.assertEquals('chromeos', capabilities['platform'].lower()) - finally: - response.close() - - -if __name__ == '__main__': - parser = optparse.OptionParser('%prog [options]') - parser.add_option('-u', '--url', dest='url', action='store', - type='string', default=None, - help=('Specifies the URL of a remote WebDriver server to ' - 'test against. If not specified, a server will be ' - 'started on localhost according to the --exe and ' - '--port flags')) - parser.add_option('-e', '--exe', dest='exe', action='store', - type='string', default=None, - help=('Path to the WebDriver server executable that should ' - 'be started for testing; This flag is ignored if ' - '--url is provided for a remote server.')) - parser.add_option('-p', '--port', dest='port', action='store', - type='int', default=8080, - help=('The port to start the WebDriver server executable ' - 'on; This flag is ignored if --url is provided for a ' - 'remote server.')) - - (options, args) = parser.parse_args() - # Strip out our flags so unittest.main() correct parses the remaining - sys.argv = sys.argv[:1] - sys.argv.extend(args) - - if options.url: - WEBDRIVER_SERVER_URL = options.url - else: - if options.port: - WEBDRIVER_PORT = options.port - if options.exe: - WEBDRIVER_EXE = options.exe - if not os.path.exists(WEBDRIVER_EXE): - parser.error('WebDriver server executable not found:\n\t%s\n' - 'Please specify a valid path with the --exe flag.' - % WEBDRIVER_EXE) - - setUpModule() - try: - unittest.main() - finally: - tearDownModule() diff --git a/third_party/mongoose/README.chromium b/third_party/mongoose/README.chromium index c8561bf..c1bf3ca 100644 --- a/third_party/mongoose/README.chromium +++ b/third_party/mongoose/README.chromium @@ -26,3 +26,6 @@ Note: There is no make file for this project, it's compiled directly in the chrome versoin of webdriver found under the directory: src/chrome/test/webdriver +Local modifications: +-Do not check for OS_POSIX, instead just check that it is not windows. + diff --git a/third_party/mongoose/mongoose.c b/third_party/mongoose/mongoose.c index 8078e63..24874e5 100644 --- a/third_party/mongoose/mongoose.c +++ b/third_party/mongoose/mongoose.c @@ -4479,10 +4479,10 @@ get_socket(struct mg_context *ctx, struct socket *sp) ctx->num_idle++; while (ctx->sq_head == ctx->sq_tail) { ts.tv_nsec = 0; -#ifdef OS_POSIX - ts.tv_sec = time(NULL) + atoi(ctx->options[OPT_IDLE_TIME]) + 1; -#elif _WIN32 +#ifdef _WIN32 ts.tv_sec = (long) (time(NULL) + atoi(ctx->options[OPT_IDLE_TIME]) + 1); +#else + ts.tv_sec = time(NULL) + atoi(ctx->options[OPT_IDLE_TIME]) + 1; #endif if (pthread_cond_timedwait(&ctx->empty_cond, &ctx->thr_mutex, &ts) != 0) { @@ -4747,4 +4747,3 @@ mg_start(void) return (ctx); } - |