diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-23 19:56:46 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-23 19:56:46 +0000 |
commit | a9f94f399a5925ef801b2856bd4ad79f2d823e77 (patch) | |
tree | e4d494e02ea773fb93fe4be092cbce1557ee6740 /chrome/test/chromedriver | |
parent | 7fbe511b49d31fcc88a7675dbc6b6d8c8013ca68 (diff) | |
download | chromium_src-a9f94f399a5925ef801b2856bd4ad79f2d823e77.zip chromium_src-a9f94f399a5925ef801b2856bd4ad79f2d823e77.tar.gz chromium_src-a9f94f399a5925ef801b2856bd4ad79f2d823e77.tar.bz2 |
Initial check-in for new ChromeDriver based on DevTools.
Introduces 3 new targets, chromedriver2_lib, chromedriver2_unittests, and chromedriver2. The latter is a shared library which can be loaded into a test/automation process and used to control chrome. The shared library exposes a function ExecuteCommand, which takes WebDriver JSON commands and returns a WebDriver JSON response.
In the future, when necessary, we may create a new chromedriver_server target which uses the chromedriver2_lib and exposes it remotely via sockets/http/whatever.
BUG=none
Review URL: https://chromiumcodereview.appspot.com/11099075
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163651 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/chromedriver')
-rw-r--r-- | chrome/test/chromedriver/OWNERS | 2 | ||||
-rw-r--r-- | chrome/test/chromedriver/chromedriver.cc | 111 | ||||
-rw-r--r-- | chrome/test/chromedriver/chromedriver.h | 35 | ||||
-rw-r--r-- | chrome/test/chromedriver/chromedriver.py | 39 | ||||
-rw-r--r-- | chrome/test/chromedriver/chromedriver_shared_library.cc | 69 | ||||
-rw-r--r-- | chrome/test/chromedriver/chromedriver_unittest.cc | 101 | ||||
-rw-r--r-- | chrome/test/chromedriver/command_executor.h | 34 | ||||
-rw-r--r-- | chrome/test/chromedriver/command_executor_impl.cc | 80 | ||||
-rw-r--r-- | chrome/test/chromedriver/command_executor_impl.h | 62 | ||||
-rw-r--r-- | chrome/test/chromedriver/command_executor_impl_unittest.cc | 59 | ||||
-rw-r--r-- | chrome/test/chromedriver/status.cc | 47 | ||||
-rw-r--r-- | chrome/test/chromedriver/status.h | 35 | ||||
-rw-r--r-- | chrome/test/chromedriver/status_unittest.cc | 30 | ||||
-rw-r--r-- | chrome/test/chromedriver/test.py | 30 |
14 files changed, 734 insertions, 0 deletions
diff --git a/chrome/test/chromedriver/OWNERS b/chrome/test/chromedriver/OWNERS new file mode 100644 index 0000000..dd1e0b4 --- /dev/null +++ b/chrome/test/chromedriver/OWNERS @@ -0,0 +1,2 @@ +kkania@chromium.org +klundberg@chromium.org diff --git a/chrome/test/chromedriver/chromedriver.cc b/chrome/test/chromedriver/chromedriver.cc new file mode 100644 index 0000000..8d9b41b --- /dev/null +++ b/chrome/test/chromedriver/chromedriver.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 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 "chrome/test/chromedriver/chromedriver.h" + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/lazy_instance.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "base/values.h" +#include "chrome/test/chromedriver/command_executor.h" +#include "chrome/test/chromedriver/command_executor_impl.h" +#include "chrome/test/chromedriver/status.h" + +namespace { + +// Guards initialization of |g_command_executor|. +base::LazyInstance<base::Lock> g_lazy_lock = LAZY_INSTANCE_INITIALIZER; + +CommandExecutor* g_command_executor = NULL; + +CommandExecutor* CreateCommandExecutor() { + return new CommandExecutorImpl(); +} + +CommandExecutorFactoryFunc g_executor_factory = &CreateCommandExecutor; + +void SetResponse(StatusCode status, + const base::Value* value, + const std::string& session_id, + std::string* response) { + base::DictionaryValue response_dict; + response_dict.SetInteger("status", status); + response_dict.Set("value", value->DeepCopy()); + response_dict.SetString("sessionId", session_id); + std::string json; + base::JSONWriter::Write(&response_dict, response); +} + +void SetError(const std::string& error_msg, + std::string* response) { + base::DictionaryValue value; + value.SetString("message", error_msg); + SetResponse(kUnknownError, &value, "", response); +} + +} // namespace + +void SetCommandExecutorFactoryForTesting(CommandExecutorFactoryFunc func) { + g_executor_factory = func; +} + +// Synchronously executes the given command. Thread safe. +// Command must be a JSON object: +// { +// "name": <string>, +// "parameters": <dictionary>, +// "sessionId": <string> +// } +// Response will always be a JSON object: +// { +// "status": <integer>, +// "value": <object>, +// "sessionId": <string> +// } +// If "status" is non-zero, "value" will be an object with a string "message" +// property which signifies the error message. +void ExecuteCommand(const std::string& command, std::string* response) { + std::string error_msg; + scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( + command, 0, NULL, &error_msg)); + if (!value.get()) { + SetError("failed to parse command: " + error_msg, response); + return; + } + base::DictionaryValue* command_dict; + if (!value->GetAsDictionary(&command_dict)) { + SetError("invalid command (must be dictionary)", response); + return; + } + std::string name; + if (!command_dict->GetString("name", &name)) { + SetError("invalid command (must contain 'name' of type string)", response); + return; + } + base::DictionaryValue* params; + if (!command_dict->GetDictionary("parameters", ¶ms)) { + SetError("invalid command (must contain 'parameters' of type dict)", + response); + return; + } + std::string session_id; + if (!command_dict->GetString("sessionId", &session_id)) { + SetError("invalid command (must contain 'sessionId' of type string)", + response); + return; + } + StatusCode out_status = kOk; + scoped_ptr<base::Value> out_value; + std::string out_session_id; + { + base::AutoLock(g_lazy_lock.Get()); + if (!g_command_executor) + g_command_executor = g_executor_factory(); + } + g_command_executor->ExecuteCommand( + name, *params, session_id, &out_status, &out_value, &out_session_id); + SetResponse(out_status, out_value.get(), out_session_id, response); +} diff --git a/chrome/test/chromedriver/chromedriver.h b/chrome/test/chromedriver/chromedriver.h new file mode 100644 index 0000000..fbad292 --- /dev/null +++ b/chrome/test/chromedriver/chromedriver.h @@ -0,0 +1,35 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_TEST_CHROMEDRIVER_CHROMEDRIVER_H_ +#define CHROME_TEST_CHROMEDRIVER_CHROMEDRIVER_H_ + +#include <string> + +class CommandExecutor; + +typedef CommandExecutor* (*CommandExecutorFactoryFunc)(); + +// Sets the function to use for creating new |CommandExecutor|s. Only +// for testing purposes. +void SetCommandExecutorFactoryForTesting(CommandExecutorFactoryFunc func); + +// Synchronously executes the given command. Thread safe. +// Command must be a JSON object: +// { +// "name": <string>, +// "parameters": <dictionary>, +// "sessionId": <string> +// } +// Response will always be a JSON object: +// { +// "status": <integer>, +// "value": <object>, +// "sessionId": <string> +// } +// If "status" is non-zero, "value" will be an object with a string "message" +// property which signifies the error message. +void ExecuteCommand(const std::string& command, std::string* response); + +#endif // CHROME_TEST_CHROMEDRIVER_CHROMEDRIVER_H_ diff --git a/chrome/test/chromedriver/chromedriver.py b/chrome/test/chromedriver/chromedriver.py new file mode 100644 index 0000000..02d395a --- /dev/null +++ b/chrome/test/chromedriver/chromedriver.py @@ -0,0 +1,39 @@ +# Copyright (c) 2012 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. + +import ctypes +import json + + +class ChromeDriver(object): + """Starts and controls a single Chrome instance on this machine.""" + + def __init__(self, lib_path): + self._lib = ctypes.CDLL(lib_path) + self._session_id = self._ExecuteCommand('newSession') + + def _ExecuteCommand(self, name, params={}, session_id=''): + cmd = { + 'name': name, + 'parameters': params, + 'sessionId': session_id + } + cmd_json = json.dumps(cmd) + response_data = ctypes.c_char_p() + response_size = ctypes.c_uint() + self._lib.ExecuteCommand( + ctypes.c_char_p(cmd_json), + ctypes.c_uint(len(cmd_json)), + ctypes.byref(response_data), + ctypes.byref(response_size)) + response_json = ctypes.string_at(response_data, response_size.value) + self._lib.Free(response_data) + return json.loads(response_json)['value'] + + def _ExecuteSessionCommand(self, name, params={}): + return self._ExecuteCommand(name, params, self._session_id) + + def Quit(self): + """Quits the browser and ends the session.""" + self._ExecuteSessionCommand('quit') diff --git a/chrome/test/chromedriver/chromedriver_shared_library.cc b/chrome/test/chromedriver/chromedriver_shared_library.cc new file mode 100644 index 0000000..73b49ef --- /dev/null +++ b/chrome/test/chromedriver/chromedriver_shared_library.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2012 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 <cstring> +#include <string> + +#include "base/at_exit.h" +#include "build/build_config.h" +#include "chrome/test/chromedriver/chromedriver.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#if defined(OS_WIN) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT __attribute__((visibility("default"))) +#endif + +namespace { + +base::AtExitManager* g_at_exit = NULL; + +} // namespace + +extern "C" { + +// Synchronously executes the given command. Thread safe. +// Every call dynamically allocates a |response| string, which must be +// deallocated by calling |Free|. This |response| string is not guaranteed +// to be null terminated, and may contain null characters within. You +// should use the given response size to construct the string. +void EXPORT ExecuteCommand( + const char* command, + unsigned int command_size, + char** response, + unsigned int* response_size) { + std::string command_str(command, command_size); + std::string json; + ExecuteCommand(command_str, &json); + *response = new char[json.length()]; + std::memcpy(*response, json.c_str(), json.length()); + *response_size = json.length(); +} + +void EXPORT Free(char* p) { + delete [] p; +} + +} // extern "C" + +#if defined(OS_WIN) +BOOL APIENTRY DllMain(HMODULE module, DWORD reason, void* reserved) { + if (reason == DLL_PROCESS_ATTACH) + g_at_exit = new base::AtExitManager(); + if (reason == DLL_PROCESS_DETACH) + delete g_at_exit; + return TRUE; +} +#else +void __attribute__((constructor)) OnLoad(void) { + g_at_exit = new base::AtExitManager(); +} +void __attribute__((destructor)) OnUnload(void) { + delete g_at_exit; +} +#endif diff --git a/chrome/test/chromedriver/chromedriver_unittest.cc b/chrome/test/chromedriver/chromedriver_unittest.cc new file mode 100644 index 0000000..5b3e248 --- /dev/null +++ b/chrome/test/chromedriver/chromedriver_unittest.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2012 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 <list> +#include <string> + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/json/json_reader.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "base/values.h" +#include "chrome/test/chromedriver/chromedriver.h" +#include "chrome/test/chromedriver/command_executor.h" +#include "chrome/test/chromedriver/status.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +void ExpectExecuteError(const std::string& command) { + std::string response; + ExecuteCommand(command, &response); + scoped_ptr<base::Value> value(base::JSONReader::Read(response)); + ASSERT_TRUE(value.get()); + base::DictionaryValue* dict; + ASSERT_TRUE(value->GetAsDictionary(&dict)); + int status; + ASSERT_TRUE(dict->GetInteger("status", &status)); + EXPECT_EQ(kUnknownError, status); +} + +class ExecutorMock : public CommandExecutor { + public: + virtual ~ExecutorMock() {} + + virtual void ExecuteCommand(const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + StatusCode* status, + scoped_ptr<base::Value>* value, + std::string* out_session_id) OVERRIDE { + EXPECT_STREQ("name", name.c_str()); + int param = 0; + EXPECT_TRUE(params.GetInteger("param", ¶m)); + EXPECT_EQ(100, param); + EXPECT_STREQ("id", session_id.c_str()); + *status = kOk; + value->reset(new base::StringValue("stuff")); + *out_session_id = "session_id"; + } + + static void CheckExecuteCommand() { + std::string response; + ::ExecuteCommand("{\"name\": \"name\", " + " \"parameters\": {\"param\": 100}, " + " \"sessionId\": \"id\"}", + &response); + scoped_ptr<base::Value> value(base::JSONReader::Read(response)); + ASSERT_TRUE(value.get()); + base::DictionaryValue* dict; + ASSERT_TRUE(value->GetAsDictionary(&dict)); + int status; + ASSERT_TRUE(dict->GetInteger("status", &status)); + std::string value_str; + ASSERT_TRUE(dict->GetString("value", &value_str)); + EXPECT_STREQ("stuff", value_str.c_str()); + EXPECT_EQ(kOk, status); + } +}; + +CommandExecutor* CreateExecutorMock() { + return new ExecutorMock(); +} + +} // namespace + +TEST(ChromeDriver, InvalidCommands) { + ExpectExecuteError("hi[]"); + ExpectExecuteError("[]"); + ExpectExecuteError( + "{\"parameters\": {}, \"sessionId\": \"\"}"); + ExpectExecuteError( + "{\"name\": 1, \"parameters\": {}, \"sessionId\": \"\"}"); + ExpectExecuteError( + "{\"name\": \"\", \"sessionId\": \"\"}"); + ExpectExecuteError( + "{\"name\": \"\", \"parameters\": 1, \"sessionId\": \"\"}"); + ExpectExecuteError( + "{\"name\": \"\", \"parameters\": {}}"); + ExpectExecuteError( + "{\"name\": \"\", \"parameters\": {}, \"sessionId\": 1}"); +} + +TEST(ChromeDriver, ExecuteCommand) { + SetCommandExecutorFactoryForTesting(&CreateExecutorMock); + ExecutorMock::CheckExecuteCommand(); +} diff --git a/chrome/test/chromedriver/command_executor.h b/chrome/test/chromedriver/command_executor.h new file mode 100644 index 0000000..db0b0f9 --- /dev/null +++ b/chrome/test/chromedriver/command_executor.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_H_ +#define CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/non_thread_safe.h" +#include "chrome/test/chromedriver/status.h" + +namespace base { +class DictionaryValue; +class Value; +} + +// Executes WebDriver commands. +class CommandExecutor { + public: + virtual ~CommandExecutor() {} + + // Executes a command synchronously. This function must be thread safe. + virtual void ExecuteCommand(const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + StatusCode* status_code, + scoped_ptr<base::Value>* value, + std::string* out_session_id) = 0; +}; + +#endif // CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_H_ diff --git a/chrome/test/chromedriver/command_executor_impl.cc b/chrome/test/chromedriver/command_executor_impl.cc new file mode 100644 index 0000000..422d0ea --- /dev/null +++ b/chrome/test/chromedriver/command_executor_impl.cc @@ -0,0 +1,80 @@ +// Copyright (c) 2012 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 "chrome/test/chromedriver/command_executor_impl.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/string_number_conversions.h" +#include "base/values.h" +#include "chrome/test/chromedriver/status.h" + +namespace { + +void ExecuteQuit( + const base::DictionaryValue& params, + Status* status, + scoped_ptr<base::Value>* value) { +} + +} // namespace + +CommandExecutorImpl::CommandExecutorImpl() + : next_session_id_(1) { + session_command_map_.insert(std::make_pair("quit", base::Bind( + &ExecuteQuit))); +} + +CommandExecutorImpl::~CommandExecutorImpl() {} + +void CommandExecutorImpl::ExecuteCommand( + const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + StatusCode* status_code, + scoped_ptr<base::Value>* value, + std::string* out_session_id) { + base::AutoLock auto_lock(lock_); + Status status(kOk); + ExecuteCommandInternal(name, params, session_id, &status, value, + out_session_id); + *status_code = status.code(); + if (status.IsError()) { + base::DictionaryValue* error = new base::DictionaryValue(); + error->SetString("message", status.message()); + value->reset(error); + } + if (!*value) + value->reset(base::Value::CreateNullValue()); +} + +void CommandExecutorImpl::ExecuteCommandInternal( + const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + Status* status, + scoped_ptr<base::Value>* value, + std::string* out_session_id) { + *out_session_id = session_id; + if (name == "newSession") { + ExecuteNewSession(out_session_id); + return; + } + + // Although most versions of the C++ std lib supposedly guarantee + // thread safety for concurrent reads, better safe than sorry. + SessionCommandMap::const_iterator iter = session_command_map_.find(name); + if (iter != session_command_map_.end()) { + SessionCommandCallback command_callback = iter->second; + base::AutoUnlock auto_unlock(lock_); + command_callback.Run(params, status, value); + return; + } + + *status = Status(kUnknownCommand, name); +} + +void CommandExecutorImpl::ExecuteNewSession(std::string* session_id) { + *session_id = base::IntToString(next_session_id_++); +} diff --git a/chrome/test/chromedriver/command_executor_impl.h b/chrome/test/chromedriver/command_executor_impl.h new file mode 100644 index 0000000..63cdc22 --- /dev/null +++ b/chrome/test/chromedriver/command_executor_impl.h @@ -0,0 +1,62 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_IMPL_H_ +#define CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_IMPL_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "chrome/test/chromedriver/command_executor.h" +#include "chrome/test/chromedriver/status.h" + +namespace base { +class DictionaryValue; +class Value; +} + +class CommandExecutorImpl : public CommandExecutor { + public: + CommandExecutorImpl(); + virtual ~CommandExecutorImpl(); + + // Overriden from CommandExecutor: + virtual void ExecuteCommand(const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + StatusCode* status_code, + scoped_ptr<base::Value>* value, + std::string* out_session_id) OVERRIDE; + + private: + typedef base::Callback<void( + const base::DictionaryValue& params, + Status* status, + scoped_ptr<base::Value>* value)> + SessionCommandCallback; + typedef std::map<std::string, SessionCommandCallback> SessionCommandMap; + + void ExecuteCommandInternal( + const std::string& name, + const base::DictionaryValue& params, + const std::string& session_id, + Status* status, + scoped_ptr<base::Value>* value, + std::string* out_session_id); + + void ExecuteNewSession(std::string* session_id); + + base::Lock lock_; + int next_session_id_; + SessionCommandMap session_command_map_; + + DISALLOW_COPY_AND_ASSIGN(CommandExecutorImpl); +}; + +#endif // CHROME_TEST_CHROMEDRIVER_COMMAND_EXECUTOR_IMPL_H_ diff --git a/chrome/test/chromedriver/command_executor_impl_unittest.cc b/chrome/test/chromedriver/command_executor_impl_unittest.cc new file mode 100644 index 0000000..0485656 --- /dev/null +++ b/chrome/test/chromedriver/command_executor_impl_unittest.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2012 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 <string> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "chrome/test/chromedriver/command_executor_impl.h" +#include "chrome/test/chromedriver/status.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CommandExecutorTest, NewSession) { + CommandExecutorImpl executor; + base::DictionaryValue empty_dict; + StatusCode status; + scoped_ptr<base::Value> value; + std::string session_id; + executor.ExecuteCommand("newSession", empty_dict, "", + &status, &value, &session_id); + ASSERT_EQ(kOk, status); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(value->IsType(base::Value::TYPE_NULL)); + ASSERT_STREQ("1", session_id.c_str()); + executor.ExecuteCommand("newSession", empty_dict, "random", + &status, &value, &session_id); + ASSERT_STREQ("2", session_id.c_str()); +} + +TEST(CommandExecutorTest, UnknownCommand) { + CommandExecutorImpl executor; + base::DictionaryValue empty_dict; + StatusCode status; + scoped_ptr<base::Value> value; + std::string session_id; + executor.ExecuteCommand("noSuchCommand", empty_dict, "session", + &status, &value, &session_id); + ASSERT_EQ(kUnknownCommand, status); + base::DictionaryValue* error; + ASSERT_TRUE(value->GetAsDictionary(&error)); + std::string error_msg; + ASSERT_TRUE(error->GetString("message", &error_msg)); + ASSERT_STREQ("unknown command: noSuchCommand", error_msg.c_str()); + ASSERT_STREQ("session", session_id.c_str()); +} + +TEST(CommandExecutorTest, Quit) { + CommandExecutorImpl executor; + base::DictionaryValue empty_dict; + StatusCode status; + scoped_ptr<base::Value> value; + std::string session_id; + executor.ExecuteCommand("quit", empty_dict, "id", + &status, &value, &session_id); + ASSERT_EQ(kOk, status); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(value->IsType(base::Value::TYPE_NULL)); + ASSERT_STREQ("id", session_id.c_str()); +} diff --git a/chrome/test/chromedriver/status.cc b/chrome/test/chromedriver/status.cc new file mode 100644 index 0000000..60e09f0 --- /dev/null +++ b/chrome/test/chromedriver/status.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2012 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 "chrome/test/chromedriver/status.h" + +namespace { + +// Returns the string equivalent of the given |ErrorCode|. +const char* DefaultMessageForStatusCode(StatusCode code) { + switch (code) { + case kOk: + return "ok"; + case kUnknownError: + return "unknown error"; + case kUnknownCommand: + return "unknown command"; + default: + return "<unknown>"; + } +} + +} // namespace + +Status::Status(StatusCode code) + : code_(code), msg_(DefaultMessageForStatusCode(code)) {} + +Status::Status(StatusCode code, const std::string& details) + : code_(code), + msg_(DefaultMessageForStatusCode(code) + std::string(": ") + details) { +} + +bool Status::IsOk() const { + return code_ == kOk; +} + +bool Status::IsError() const { + return code_ != kOk; +} + +StatusCode Status::code() const { + return code_; +} + +const std::string& Status::message() const { + return msg_; +} diff --git a/chrome/test/chromedriver/status.h b/chrome/test/chromedriver/status.h new file mode 100644 index 0000000..8f5a75b --- /dev/null +++ b/chrome/test/chromedriver/status.h @@ -0,0 +1,35 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_TEST_CHROMEDRIVER_STATUS_H_ +#define CHROME_TEST_CHROMEDRIVER_STATUS_H_ + +#include <string> + +// WebDriver standard status codes. +enum StatusCode { + kOk = 0, + kUnknownCommand = 9, + kUnknownError = 13 +}; + +// Represents a WebDriver status, which may be an error or ok. +class Status { + public: + explicit Status(StatusCode code); + Status(StatusCode code, const std::string& details); + + bool IsOk() const; + bool IsError() const; + + StatusCode code() const; + + const std::string& message() const; + + private: + StatusCode code_; + std::string msg_; +}; + +#endif // CHROME_TEST_CHROMEDRIVER_STATUS_H_ diff --git a/chrome/test/chromedriver/status_unittest.cc b/chrome/test/chromedriver/status_unittest.cc new file mode 100644 index 0000000..a585afb --- /dev/null +++ b/chrome/test/chromedriver/status_unittest.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2012 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 "chrome/test/chromedriver/status.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(StatusTest, Ok) { + Status ok(kOk); + ASSERT_TRUE(ok.IsOk()); + ASSERT_FALSE(ok.IsError()); + ASSERT_EQ(kOk, ok.code()); + ASSERT_STREQ("ok", ok.message().c_str()); +} + +TEST(StatusTest, Error) { + Status ok(kUnknownCommand); + ASSERT_FALSE(ok.IsOk()); + ASSERT_TRUE(ok.IsError()); + ASSERT_EQ(kUnknownCommand, ok.code()); + ASSERT_STREQ("unknown command", ok.message().c_str()); +} + +TEST(StatusTest, ErrorWithDetails) { + Status ok(kUnknownError, "something happened"); + ASSERT_FALSE(ok.IsOk()); + ASSERT_TRUE(ok.IsError()); + ASSERT_EQ(kUnknownError, ok.code()); + ASSERT_STREQ("unknown error: something happened", ok.message().c_str()); +} diff --git a/chrome/test/chromedriver/test.py b/chrome/test/chromedriver/test.py new file mode 100644 index 0000000..34ea2636 --- /dev/null +++ b/chrome/test/chromedriver/test.py @@ -0,0 +1,30 @@ +# Copyright (c) 2012 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. + +"""End to end tests for ChromeDriver.""" + +import ctypes +import os +import sys +import unittest + +import chromedriver + + +class ChromeDriverTest(unittest.TestCase): + """End to end tests for ChromeDriver.""" + + def testStartStop(self): + driver = chromedriver.ChromeDriver(_CHROMEDRIVER_LIB) + driver.Quit() + +if __name__ == '__main__': + if len(sys.argv) != 2: + print 'Usage: %s <path_to_chromedriver_so>' % __file__ + sys.exit(1) + global _CHROMEDRIVER_LIB + _CHROMEDRIVER_LIB = os.path.abspath(sys.argv[1]) + all_tests_suite = unittest.defaultTestLoader.loadTestsFromModule( + sys.modules[__name__]) + unittest.TextTestRunner().run(all_tests_suite) |