blob: 25f03cb9325f591c8fec47a010168aee605a88d1 [file] [log] [blame]
// Copyright (c) 2011 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.
#include <signal.h>
#include <stdlib.h>
#if defined(OS_WIN)
#include <windows.h>
#endif
#include <iostream>
#include <fstream>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_number_conversions.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_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/webdriver/commands/alert_commands.h"
#include "chrome/test/webdriver/commands/appcache_status_command.h"
#include "chrome/test/webdriver/commands/browser_connection_commands.h"
#include "chrome/test/webdriver/commands/cookie_commands.h"
#include "chrome/test/webdriver/commands/create_session.h"
#include "chrome/test/webdriver/commands/execute_async_script_command.h"
#include "chrome/test/webdriver/commands/execute_command.h"
#include "chrome/test/webdriver/commands/find_element_commands.h"
#include "chrome/test/webdriver/commands/navigate_commands.h"
#include "chrome/test/webdriver/commands/mouse_commands.h"
#include "chrome/test/webdriver/commands/screenshot_command.h"
#include "chrome/test/webdriver/commands/session_with_id.h"
#include "chrome/test/webdriver/commands/set_timeout_commands.h"
#include "chrome/test/webdriver/commands/source_command.h"
#include "chrome/test/webdriver/commands/target_locator_commands.h"
#include "chrome/test/webdriver/commands/title_command.h"
#include "chrome/test/webdriver/commands/url_command.h"
#include "chrome/test/webdriver/commands/webelement_commands.h"
#include "chrome/test/webdriver/webdriver_dispatch.h"
#include "chrome/test/webdriver/webdriver_logging.h"
#include "chrome/test/webdriver/webdriver_session_manager.h"
#include "chrome/test/webdriver/webdriver_util.h"
#include "third_party/mongoose/mongoose.h"
#if defined(OS_WIN)
#include <time.h>
#elif defined(OS_POSIX)
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif
namespace webdriver {
void InitCallbacks(struct mg_context* ctx, Dispatcher* dispatcher,
base::WaitableEvent* shutdown_event,
bool forbid_other_requests) {
dispatcher->AddShutdown("/shutdown", shutdown_event);
dispatcher->AddHealthz("/status");
dispatcher->AddLog("/log");
dispatcher->Add<CreateSession>("/session");
// WebElement commands
dispatcher->Add<FindOneElementCommand>( "/session/*/element");
dispatcher->Add<FindManyElementsCommand>("/session/*/elements");
dispatcher->Add<ActiveElementCommand>( "/session/*/element/active");
dispatcher->Add<FindOneElementCommand>( "/session/*/element/*/element");
dispatcher->Add<FindManyElementsCommand>("/session/*/elements/*/elements");
dispatcher->Add<ElementAttributeCommand>("/session/*/element/*/attribute/*");
dispatcher->Add<ElementCssCommand>( "/session/*/element/*/css/*");
dispatcher->Add<ElementClearCommand>( "/session/*/element/*/clear");
dispatcher->Add<ElementDisplayedCommand>("/session/*/element/*/displayed");
dispatcher->Add<ElementEnabledCommand>( "/session/*/element/*/enabled");
dispatcher->Add<ElementEqualsCommand>( "/session/*/element/*/equals/*");
dispatcher->Add<ElementLocationCommand>( "/session/*/element/*/location");
dispatcher->Add<ElementLocationInViewCommand>(
"/session/*/element/*/location_in_view");
dispatcher->Add<ElementNameCommand>( "/session/*/element/*/name");
dispatcher->Add<ElementSelectedCommand>("/session/*/element/*/selected");
dispatcher->Add<ElementSizeCommand>( "/session/*/element/*/size");
dispatcher->Add<ElementSubmitCommand>( "/session/*/element/*/submit");
dispatcher->Add<ElementTextCommand>( "/session/*/element/*/text");
dispatcher->Add<ElementToggleCommand>( "/session/*/element/*/toggle");
dispatcher->Add<ElementValueCommand>( "/session/*/element/*/value");
dispatcher->Add<ScreenshotCommand>("/session/*/screenshot");
// Mouse Commands
dispatcher->Add<MoveAndClickCommand>("/session/*/element/*/click");
dispatcher->Add<DragCommand>( "/session/*/element/*/drag");
dispatcher->Add<HoverCommand>( "/session/*/element/*/hover");
dispatcher->Add<MoveToCommand>( "/session/*/moveto");
dispatcher->Add<ClickCommand>( "/session/*/click");
dispatcher->Add<ButtonDownCommand>( "/session/*/buttondown");
dispatcher->Add<ButtonUpCommand>( "/session/*/buttonup");
dispatcher->Add<DoubleClickCommand>("/session/*/doubleclick");
// All session based commands should be listed after the element based
// commands to avoid potential mapping conflicts from an overzealous
// wildcard match. For example, /session/*/title maps to the handler to
// fetch the page title. If mapped first, this would overwrite the handler
// for /session/*/element/*/attribute/title, which should fetch the title
// attribute of the element.
dispatcher->Add<AcceptAlertCommand>( "/session/*/accept_alert");
dispatcher->Add<AlertTextCommand>( "/session/*/alert_text");
dispatcher->Add<BackCommand>( "/session/*/back");
dispatcher->Add<DismissAlertCommand>( "/session/*/dismiss_alert");
dispatcher->Add<ExecuteCommand>( "/session/*/execute");
dispatcher->Add<ExecuteAsyncScriptCommand>(
"/session/*/execute_async");
dispatcher->Add<ForwardCommand>( "/session/*/forward");
dispatcher->Add<SwitchFrameCommand>( "/session/*/frame");
dispatcher->Add<RefreshCommand>( "/session/*/refresh");
dispatcher->Add<SourceCommand>( "/session/*/source");
dispatcher->Add<TitleCommand>( "/session/*/title");
dispatcher->Add<URLCommand>( "/session/*/url");
dispatcher->Add<WindowCommand>( "/session/*/window");
dispatcher->Add<WindowHandleCommand>( "/session/*/window_handle");
dispatcher->Add<WindowHandlesCommand>("/session/*/window_handles");
dispatcher->Add<SetAsyncScriptTimeoutCommand>(
"/session/*/timeouts/async_script");
dispatcher->Add<ImplicitWaitCommand>( "/session/*/timeouts/implicit_wait");
// Cookie functions.
dispatcher->Add<CookieCommand>( "/session/*/cookie");
dispatcher->Add<NamedCookieCommand>("/session/*/cookie/*");
dispatcher->Add<BrowserConnectionCommand>("/session/*/browser_connection");
dispatcher->Add<AppCacheStatusCommand>("/session/*/application_cache/status");
// Since the /session/* is a wild card that would match the above URIs, this
// line MUST be after all other webdriver command callbacks.
dispatcher->Add<SessionWithID>("/session/*");
if (forbid_other_requests)
dispatcher->ForbidAllOtherRequests();
}
} // 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;
base::WaitableEvent shutdown_event(false, false);
CommandLine::Init(argc, argv);
CommandLine* cmd_line = CommandLine::ForCurrentProcess();
#if defined(OS_POSIX)
signal(SIGPIPE, SIG_IGN);
#endif
srand((unsigned int)time(NULL));
// 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;
std::string url_base;
bool verbose = false;
if (cmd_line->HasSwitch("port"))
port = cmd_line->GetSwitchValueASCII("port");
// The 'root' flag allows the user to specify a location to serve files from.
// If it is not given, a callback will be registered to forbid all file
// requests.
if (cmd_line->HasSwitch("root"))
root = cmd_line->GetSwitchValueASCII("root");
if (cmd_line->HasSwitch("url-base"))
url_base = cmd_line->GetSwitchValueASCII("url-base");
// Whether or not to do verbose logging.
if (cmd_line->HasSwitch("verbose"))
verbose = true;
webdriver::InitWebDriverLogging(
verbose ? logging::LOG_INFO : logging::LOG_WARNING);
webdriver::SessionManager* manager = webdriver::SessionManager::GetInstance();
manager->set_port(port);
manager->set_url_base(url_base);
// Initialize SHTTPD context.
// Listen on port 9515 or port specified on command line.
// TODO(jmikhail) Maybe add port 9516 as a secure connection.
ctx = mg_start();
if (!SetMongooseOptions(ctx, port, root)) {
mg_stop(ctx);
#if defined(OS_WIN)
return WSAEADDRINUSE;
#else
return EADDRINUSE;
#endif
}
webdriver::Dispatcher dispatcher(ctx, url_base);
webdriver::InitCallbacks(ctx, &dispatcher, &shutdown_event, root.empty());
// 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
<< "version=" << chrome::kChromeVersion << std::endl;
// 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
// message loop gracefully.
mg_stop(ctx);
return (EXIT_SUCCESS);
}