Commit f887493a authored by klm@google.com's avatar klm@google.com

Logging API in chromedriver2.

Review URL: https://chromiumcodereview.appspot.com/14263024

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195198 0039d316-1c4b-4281-b951-d872f2087c98
parent caab5725
......@@ -783,6 +783,8 @@
'test/chromedriver/chrome/devtools_client_impl.cc',
'test/chromedriver/chrome/devtools_client_impl.h',
'test/chromedriver/chrome/devtools_event_listener.h',
'test/chromedriver/chrome/devtools_event_logger.h',
'test/chromedriver/chrome/devtools_event_logger.cc',
'test/chromedriver/chrome/devtools_http_client.cc',
'test/chromedriver/chrome/devtools_http_client.h',
'test/chromedriver/chrome/dom_tracker.cc',
......@@ -941,6 +943,8 @@
'test/chromedriver/keycode_text_conversion_mac.mm',
'test/chromedriver/keycode_text_conversion_win.cc',
'test/chromedriver/keycode_text_conversion_x.cc',
'test/chromedriver/logging.cc',
'test/chromedriver/logging.h',
'test/chromedriver/session.cc',
'test/chromedriver/session.h',
'test/chromedriver/session_commands.cc',
......@@ -1024,6 +1028,7 @@
'test/chromedriver/capabilities_unittest.cc',
'test/chromedriver/chrome/chrome_finder_unittest.cc',
'test/chromedriver/chrome/devtools_client_impl_unittest.cc',
'test/chromedriver/chrome/devtools_event_logger_unittest.cc',
'test/chromedriver/chrome/devtools_http_client_unittest.cc',
'test/chromedriver/chrome/dom_tracker_unittest.cc',
'test/chromedriver/chrome/frame_tracker_unittest.cc',
......@@ -1044,6 +1049,7 @@
'test/chromedriver/commands_unittest.cc',
'test/chromedriver/fake_session_accessor.cc',
'test/chromedriver/fake_session_accessor.h',
'test/chromedriver/logging_unittest.cc',
'test/chromedriver/server/http_handler_unittest.cc',
'test/chromedriver/server/http_response_unittest.cc',
'test/chromedriver/session_commands_unittest.cc',
......
......@@ -201,6 +201,21 @@ Status ParseAndroidChromeCapabilities(const base::DictionaryValue& desired_caps,
return Status(kOk);
}
Status ParseLoggingPrefs(const base::DictionaryValue& desired_caps,
Capabilities* capabilities) {
const base::Value* logging_prefs = NULL;
if (desired_caps.Get("loggingPrefs", &logging_prefs)) {
const base::DictionaryValue* logging_prefs_dict = NULL;
if (!logging_prefs->GetAsDictionary(&logging_prefs_dict)) {
return Status(kUnknownError, "'loggingPrefs' must be a dictionary");
}
// TODO(klm): verify log types.
// TODO(klm): verify log levels.
capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy());
}
return Status(kOk);
}
} // namespace
Capabilities::Capabilities() : command(CommandLine::NO_PROGRAM) {}
......@@ -212,7 +227,10 @@ bool Capabilities::IsAndroid() const {
}
Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
Status status = ParseAndroidChromeCapabilities(desired_caps, this);
Status status = ParseLoggingPrefs(desired_caps, this);
if (status.IsError())
return status;
status = ParseAndroidChromeCapabilities(desired_caps, this);
if (status.IsError())
return status;
if (IsAndroid())
......
......@@ -34,6 +34,7 @@ struct Capabilities {
scoped_ptr<base::DictionaryValue> prefs;
scoped_ptr<base::DictionaryValue> local_state;
std::vector<std::string> extensions;
scoped_ptr<base::DictionaryValue> logging_prefs;
};
#endif // CHROME_TEST_CHROMEDRIVER_CAPABILITIES_H_
......@@ -252,3 +252,27 @@ TEST(ParseCapabilities, MissingSettingForManualProxy) {
Status status = capabilities.Parse(caps);
ASSERT_FALSE(status.IsOk());
}
TEST(ParseCapabilities, LoggingPrefsOk) {
Capabilities capabilities;
base::DictionaryValue logging_prefs;
logging_prefs.SetString("Network", "INFO");
base::DictionaryValue caps;
caps.Set("loggingPrefs", logging_prefs.DeepCopy());
Status status = capabilities.Parse(caps);
ASSERT_TRUE(status.IsOk());
ASSERT_TRUE(capabilities.logging_prefs.get());
ASSERT_EQ(1u, capabilities.logging_prefs->size());
std::string log_level;
ASSERT_TRUE(capabilities.logging_prefs->GetString("Network", &log_level));
ASSERT_STREQ("INFO", log_level.c_str());
}
TEST(ParseCapabilities, LoggingPrefsNotDict) {
Capabilities capabilities;
base::DictionaryValue caps;
caps.SetString("loggingPrefs", "INFO");
Status status = capabilities.Parse(caps);
ASSERT_FALSE(status.IsOk());
}
......@@ -10,8 +10,9 @@
ChromeAndroidImpl::ChromeAndroidImpl(
scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no)
: ChromeImpl(client.Pass(), version, build_no) {}
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers)
: ChromeImpl(client.Pass(), version, build_no, devtools_event_loggers) {}
ChromeAndroidImpl::~ChromeAndroidImpl() {}
......
......@@ -5,6 +5,7 @@
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_ANDROID_IMPL_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_ANDROID_IMPL_H_
#include <list>
#include <string>
#include "base/compiler_specific.h"
......@@ -15,9 +16,11 @@ class DevToolsHttpClient;
class ChromeAndroidImpl : public ChromeImpl {
public:
ChromeAndroidImpl(scoped_ptr<DevToolsHttpClient> client,
ChromeAndroidImpl(
scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no);
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers);
virtual ~ChromeAndroidImpl();
// Overridden from Chrome:
......
......@@ -20,10 +20,11 @@ ChromeDesktopImpl::ChromeDesktopImpl(
scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
base::ProcessHandle process,
base::ScopedTempDir* user_data_dir,
base::ScopedTempDir* extension_dir)
: ChromeImpl(client.Pass(), version, build_no),
: ChromeImpl(client.Pass(), version, build_no, devtools_event_loggers),
process_(process) {
if (user_data_dir->IsValid())
CHECK(user_data_dir_.Set(user_data_dir->Take()));
......
......@@ -5,6 +5,7 @@
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_DESKTOP_IMPL_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_DESKTOP_IMPL_H_
#include <list>
#include <string>
#include "base/compiler_specific.h"
......@@ -22,6 +23,7 @@ class ChromeDesktopImpl : public ChromeImpl {
scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
base::ProcessHandle process,
base::ScopedTempDir* user_data_dir,
base::ScopedTempDir* extension_dir);
......
......@@ -4,7 +4,9 @@
#include "chrome/test/chromedriver/chrome/chrome_impl.h"
#include "base/logging.h"
#include "chrome/test/chromedriver/chrome/devtools_client.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/devtools_http_client.h"
#include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
#include "chrome/test/chromedriver/chrome/status.h"
......@@ -53,8 +55,16 @@ Status ChromeImpl::GetWebViewIds(std::list<std::string>* web_view_ids) {
}
}
if (!found) {
scoped_ptr<DevToolsClient> client(
devtools_http_client_->CreateClient(view.id));
for (std::list<DevToolsEventLogger*>::const_iterator logger =
devtools_event_loggers_.begin();
logger != devtools_event_loggers_.end(); ++logger) {
client->AddListener(*logger);
// Logger's OnConnected will fire when DevToolsClient connects later.
}
web_views_.push_back(make_linked_ptr(new WebViewImpl(
view.id, devtools_http_client_->CreateClient(view.id))));
view.id, client.Pass())));
}
}
......@@ -131,10 +141,12 @@ Status ChromeImpl::GetAutomationExtension(AutomationExtension** extension) {
ChromeImpl::ChromeImpl(
scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no)
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers)
: devtools_http_client_(client.Pass()),
version_(version),
build_no_(build_no) {}
build_no_(build_no),
devtools_event_loggers_(devtools_event_loggers) {}
Status ChromeImpl::GetDialogManagerForOpenDialog(
JavaScriptDialogManager** manager) {
......
......@@ -14,6 +14,7 @@
#include "chrome/test/chromedriver/chrome/chrome.h"
class AutomationExtension;
class DevToolsEventLogger;
class DevToolsHttpClient;
class JavaScriptDialogManager;
class Status;
......@@ -42,7 +43,8 @@ class ChromeImpl : public Chrome {
protected:
ChromeImpl(scoped_ptr<DevToolsHttpClient> client,
const std::string& version,
int build_no);
int build_no,
const std::list<DevToolsEventLogger*>& devtools_event_loggers);
scoped_ptr<DevToolsHttpClient> devtools_http_client_;
......@@ -56,6 +58,7 @@ class ChromeImpl : public Chrome {
// Web views in this list are in the same order as they are opened.
WebViewList web_views_;
std::list<DevToolsEventLogger*> devtools_event_loggers_;
};
#endif // CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_IMPL_H_
// Copyright (c) 2013 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 <stdint.h>
#include "base/basictypes.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_client.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/status.h"
DevToolsEventLogger::DevToolsEventLogger(
const std::string& log_type,
const std::vector<std::string>& domains,
const std::string& logging_level)
: log_type_(log_type),
domains_(domains),
logging_level_(logging_level),
log_entries_(new base::ListValue()) {
VLOG(1) << "DevToolsEventLogger(" <<
log_type_ << ", " << logging_level_ << ")";
}
DevToolsEventLogger::~DevToolsEventLogger() {
VLOG(1) << "Log type '" << log_type_ <<
"' lost " << log_entries_->GetSize() << " entries on destruction";
}
const std::string& DevToolsEventLogger::GetLogType() {
return log_type_;
}
static const std::string GetDomainEnableCommand(const std::string& domain) {
if ("Timeline" == domain) {
return "Timeline.start";
} else {
return domain + ".enable";
}
}
Status DevToolsEventLogger::OnConnected(DevToolsClient* client) {
base::DictionaryValue params; // All our enable commands have empty params.
scoped_ptr<base::DictionaryValue> result;
for (std::vector<std::string>::const_iterator domain = domains_.begin();
domain != domains_.end(); ++domain) {
const std::string command = GetDomainEnableCommand(*domain);
VLOG(1) << "Log type '" << log_type_ << "' sending command: " << command;
Status status = client->SendCommandAndGetResult(command, params, &result);
// The client may or may not be connected, e.g. from AddDevToolsClient().
if (status.IsError() && status.code() != kDisconnected) {
return status;
}
}
return Status(kOk);
}
scoped_ptr<base::ListValue> DevToolsEventLogger::GetAndClearLogEntries() {
scoped_ptr<base::ListValue> ret(log_entries_.release());
log_entries_.reset(new base::ListValue());
return ret.Pass();
}
bool DevToolsEventLogger::ShouldLogEvent(const std::string& method) {
for (std::vector<std::string>::const_iterator domain = domains_.begin();
domain != domains_.end(); ++domain) {
size_t prefix_len = domain->length();
if (method.length() > prefix_len && method[prefix_len] == '.' &&
StartsWithASCII(method, *domain, true)) {
return true;
}
}
return false;
}
scoped_ptr<DictionaryValue> DevToolsEventLogger::GetLogEntry(
DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) {
// Get the log event timestamp ASAP. TODO(klm): extract from params?
double timestamp_epoch_ms = base::Time::Now().ToJsTime();
// Form JSON with a writer, verified same performance as concatenation.
base::DictionaryValue log_message_dict;
log_message_dict.SetString("webview", client->GetId());
log_message_dict.SetString("message.method", method);
log_message_dict.Set("message.params", params.DeepCopy());
std::string log_message_json;
base::JSONWriter::Write(&log_message_dict, &log_message_json);
scoped_ptr<base::DictionaryValue> log_entry_dict(new base::DictionaryValue());
log_entry_dict->SetDouble("timestamp",
static_cast<int64>(timestamp_epoch_ms));
log_entry_dict->SetString("level", logging_level_);
log_entry_dict->SetString("message", log_message_json);
return log_entry_dict.Pass();
}
void DevToolsEventLogger::OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) {
if (!ShouldLogEvent(method)) {
return;
}
scoped_ptr<DictionaryValue> entry = GetLogEntry(client, method, params);
log_entries_->Append(entry.release());
}
// Copyright (c) 2013 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_CHROME_DEVTOOLS_EVENT_LOGGER_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_DEVTOOLS_EVENT_LOGGER_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
#include "chrome/test/chromedriver/chrome/status.h"
// Accumulates DevTools events of a given type for use in the Logging API.
// Tracks all WebViews of a given Chrome, via their respective DevToolsClients.
//
// A log message has the following JSON structure:
// {
// "level": logging_level,
// "timestamp": <milliseconds since epoch>,
// "message": <JSON string described below>
// }
// The message attribute is a JSON string of the following structure:
// {
// "webview": <originating WebView ID>,
// "message": { "method": "...", "params": { ... }} // DevTools message.
// }
class DevToolsEventLogger : public DevToolsEventListener {
public:
explicit DevToolsEventLogger(const std::string& log_type,
const std::vector<std::string>& domains,
const std::string& logging_level);
virtual ~DevToolsEventLogger();
const std::string& GetLogType();
scoped_ptr<base::ListValue> GetAndClearLogEntries();
virtual Status OnConnected(DevToolsClient* client) OVERRIDE;
virtual void OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE;
private:
virtual bool ShouldLogEvent(const std::string& method);
virtual scoped_ptr<DictionaryValue> GetLogEntry(
DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params);
const std::string log_type_;
const std::vector<std::string> domains_;
const std::string logging_level_;
scoped_ptr<ListValue> log_entries_;
DISALLOW_COPY_AND_ASSIGN(DevToolsEventLogger);
};
#endif // CHROME_TEST_CHROMEDRIVER_CHROME_DEVTOOLS_EVENT_LOGGER_H_
// Copyright (c) 2013 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 "base/format_macros.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class FakeDevToolsClient : public StubDevToolsClient {
public:
explicit FakeDevToolsClient(const std::string& id) : id_(id) {}
virtual ~FakeDevToolsClient() {}
std::string PopSentCommand() {
std::string command;
if (!sent_command_queue_.empty()) {
command = sent_command_queue_.front();
sent_command_queue_.pop_front();
}
return command;
}
void TriggerEvent(const std::string& method) {
base::DictionaryValue empty_params;
listener_->OnEvent(this, method, empty_params);
}
// Overridden from DevToolsClient:
virtual Status ConnectIfNecessary() OVERRIDE {
return listener_->OnConnected(this);
}
virtual Status SendCommandAndGetResult(
const std::string& method,
const base::DictionaryValue& params,
scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
sent_command_queue_.push_back(method);
return Status(kOk);
}
virtual void AddListener(DevToolsEventListener* listener) OVERRIDE {
listener_ = listener;
}
const std::string& GetId() OVERRIDE {
return id_;
}
private:
const std::string id_;
std::list<std::string> sent_command_queue_;
DevToolsEventListener* listener_;
};
scoped_ptr<DictionaryValue> ParseDictionary(const std::string& json) {
std::string error;
scoped_ptr<Value> value(base::JSONReader::ReadAndReturnError(
json, base::JSON_PARSE_RFC, NULL, &error));
if (NULL == value) {
SCOPED_TRACE(json.c_str());
SCOPED_TRACE(error.c_str());
ADD_FAILURE();
return scoped_ptr<DictionaryValue>(NULL);
}
DictionaryValue* dict = 0;
if (!value->GetAsDictionary(&dict)) {
SCOPED_TRACE("JSON object is not a dictionary");
ADD_FAILURE();
return scoped_ptr<DictionaryValue>(NULL);
}
return scoped_ptr<DictionaryValue>(dict->DeepCopy());
}
void ValidateLogEntry(base::ListValue *entries,
int index,
const char* expect_webview,
const char* expect_method,
const char* expect_level) {
const base::DictionaryValue *entry;
ASSERT_TRUE(entries->GetDictionary(index, &entry));
std::string message_json;
ASSERT_TRUE(entry->GetString("message", &message_json));
scoped_ptr<base::DictionaryValue> message(ParseDictionary(message_json));
std::string level;
EXPECT_TRUE(entry->GetString("level", &level));
EXPECT_STREQ(expect_level, level.c_str());
double timestamp = 0;
EXPECT_TRUE(entry->GetDouble("timestamp", &timestamp));
EXPECT_LT(0, timestamp);
std::string webview;
EXPECT_TRUE(message->GetString("webview", &webview));
EXPECT_STREQ(expect_webview, webview.c_str());
std::string method;
EXPECT_TRUE(message->GetString("message.method", &method));
EXPECT_STREQ(expect_method, method.c_str());
DictionaryValue* params;
EXPECT_TRUE(message->GetDictionary("message.params", &params));
EXPECT_EQ(0u, params->size());
}
} // namespace
TEST(DevToolsEventLogger, OneClientMultiDomains) {
FakeDevToolsClient client("webview-1");
std::vector<std::string> domains;
domains.push_back("Page");
domains.push_back("Network");
domains.push_back("Timeline");
DevToolsEventLogger logger("mylog", domains, "INFO");
client.AddListener(&logger);
logger.OnConnected(&client);
EXPECT_STREQ("Page.enable", client.PopSentCommand().c_str());
EXPECT_STREQ("Network.enable", client.PopSentCommand().c_str());
EXPECT_STREQ("Timeline.start", client.PopSentCommand().c_str());
EXPECT_STREQ("", client.PopSentCommand().c_str());
client.TriggerEvent("Network.gaga");
client.TriggerEvent("Page.ulala");
client.TriggerEvent("Console.bad"); // Ignore -- different domain.
scoped_ptr<base::ListValue> entries(logger.GetAndClearLogEntries());
ASSERT_EQ(2u, entries->GetSize());
ValidateLogEntry(entries.get(), 0, "webview-1", "Network.gaga", "INFO");
ValidateLogEntry(entries.get(), 1, "webview-1", "Page.ulala", "INFO");
// Repeat get returns nothing.
scoped_ptr<base::ListValue> no_entries(logger.GetAndClearLogEntries());
EXPECT_EQ(0u, no_entries->GetSize());
EXPECT_STREQ("", client.PopSentCommand().c_str()); // No more commands sent.
}
TEST(DevToolsEventLogger, MultiClientsOneDomain) {
FakeDevToolsClient client1("webview-1");
FakeDevToolsClient client2("webview-2");
std::vector<std::string> domains;
domains.push_back("Console");
DevToolsEventLogger logger("mylog", domains, "INFO");
client1.AddListener(&logger);
client2.AddListener(&logger);
logger.OnConnected(&client1);
logger.OnConnected(&client2);
EXPECT_STREQ("Console.enable", client1.PopSentCommand().c_str());
EXPECT_STREQ("", client1.PopSentCommand().c_str());
EXPECT_STREQ("Console.enable", client2.PopSentCommand().c_str());
EXPECT_STREQ("", client2.PopSentCommand().c_str());
// OnConnected sends the enable command only to that client, not others.
client1.ConnectIfNecessary();
EXPECT_STREQ("Console.enable", client1.PopSentCommand().c_str());
EXPECT_STREQ("", client1.PopSentCommand().c_str());
EXPECT_STREQ("", client2.PopSentCommand().c_str());
client1.TriggerEvent("Console.gaga1");
client2.TriggerEvent("Console.gaga2");
scoped_ptr<base::ListValue> entries(logger.GetAndClearLogEntries());
ASSERT_EQ(2u, entries->GetSize());
ValidateLogEntry(entries.get(), 0, "webview-1", "Console.gaga1", "INFO");
ValidateLogEntry(entries.get(), 1, "webview-2", "Console.gaga2", "INFO");
}
......@@ -177,10 +177,12 @@ Status WaitForDevToolsAndCheckVersion(
return Status(kUnknownError, "unable to discover open pages");
}
Status LaunchDesktopChrome(URLRequestContextGetter* context_getter,
Status LaunchDesktopChrome(
URLRequestContextGetter* context_getter,
int port,
const SyncWebSocketFactory& socket_factory,
const Capabilities& capabilities,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
scoped_ptr<Chrome>* chrome) {
CommandLine command(CommandLine::NO_PROGRAM);
base::ScopedTempDir user_data_dir;
......@@ -245,15 +247,17 @@ Status LaunchDesktopChrome(URLRequestContextGetter* context_getter,
return status;
}
chrome->reset(new ChromeDesktopImpl(
devtools_client.Pass(), version, build_no, process, &user_data_dir,
&extension_dir));
devtools_client.Pass(), version, build_no, devtools_event_loggers,
process, &user_data_dir, &extension_dir));
return Status(kOk);
}
Status LaunchAndroidChrome(URLRequestContextGetter* context_getter,
Status LaunchAndroidChrome(
URLRequestContextGetter* context_getter,
int port,
const SyncWebSocketFactory& socket_factory,
const Capabilities& capabilities,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
scoped_ptr<Chrome>* chrome) {
// TODO(frankf): Figure out how this should be installed to
// make this work for all platforms.
......@@ -283,23 +287,27 @@ Status LaunchAndroidChrome(URLRequestContextGetter* context_getter,
return status;
chrome->reset(new ChromeAndroidImpl(
devtools_client.Pass(), version, build_no));
devtools_client.Pass(), version, build_no, devtools_event_loggers));
return Status(kOk);
}
} // namespace
Status LaunchChrome(URLRequestContextGetter* context_getter,
Status LaunchChrome(
URLRequestContextGetter* context_getter,
int port,
const SyncWebSocketFactory& socket_factory,
const Capabilities& capabilities,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
scoped_ptr<Chrome>* chrome) {
if (capabilities.IsAndroid()) {
return LaunchAndroidChrome(
context_getter, port, socket_factory, capabilities, chrome);
context_getter, port, socket_factory, capabilities,
devtools_event_loggers, chrome);
} else {
return LaunchDesktopChrome(
context_getter, port, socket_factory, capabilities, chrome);
context_getter, port, socket_factory, capabilities,
devtools_event_loggers, chrome);
}
}
......
......@@ -5,6 +5,7 @@
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_LAUNCHER_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_LAUNCHER_H_
#include <list>
#include <string>
#include <vector>
......@@ -14,6 +15,7 @@
#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
class CommandLine;
class DevToolsEventLogger;
namespace base {
class DictionaryValue;
......@@ -24,10 +26,12 @@ class Chrome;
class Status;
class URLRequestContextGetter;
Status LaunchChrome(URLRequestContextGetter* context_getter,
Status LaunchChrome(
URLRequestContextGetter* context_getter,
int port,
const SyncWebSocketFactory& socket_factory,
const Capabilities& capabilities,
const std::list<DevToolsEventLogger*>& devtools_event_loggers,
scoped_ptr<Chrome>* chrome);
namespace internal {
......
......@@ -228,6 +228,10 @@ void CommandExecutorImpl::Init() {
base::Bind(&ExecuteSetWindowSize);
session_command_map[CommandNames::kMaximizeWindow] =
base::Bind(&ExecuteMaximizeWindow);
session_command_map[CommandNames::kGetAvailableLogTypes] =
base::Bind(&ExecuteGetAvailableLogTypes);
session_command_map[CommandNames::kGetLog] =
base::Bind(&ExecuteGetLog);
// Wrap SessionCommand into non-session Command.
base::Callback<Status(
......
......@@ -4,6 +4,8 @@
#include "chrome/test/chromedriver/commands.h"
#include <list>
#include "base/stringprintf.h"
#include "base/sys_info.h"
#include "base/values.h"
......@@ -11,10 +13,12 @@
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/chrome_android_impl.h"
#include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/version.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
#include "chrome/test/chromedriver/chrome_launcher.h"
#include "chrome/test/chromedriver/logging.h"
#include "chrome/test/chromedriver/net/net_util.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"
#include "chrome/test/chromedriver/session.h"
......@@ -62,9 +66,17 @@ Status ExecuteNewSession(
if (status.IsError())
return status;
// Create DevToolsEventLoggers, fail if log levels are invalid.
ScopedVector<DevToolsEventLogger> devtools_event_loggers;
status = CreateLoggers(capabilities, &devtools_event_loggers);
if (status.IsError())
return status;
scoped_ptr<Chrome> chrome;
std::list<DevToolsEventLogger*> devtools_event_logger_list(
devtools_event_loggers.begin(), devtools_event_loggers.end());
status = LaunchChrome(context_getter, port, socket_factory,
capabilities, &chrome);
capabilities, devtools_event_logger_list, &chrome);
if (status.IsError())
return status;
......@@ -80,6 +92,7 @@ Status ExecuteNewSession(
if (new_id.empty())
new_id = GenerateId();
scoped_ptr<Session> session(new Session(new_id, chrome.Pass()));
session->devtools_event_loggers.swap(devtools_event_loggers);
if (!session->thread.Start()) {
chrome->Quit();
return Status(kUnknownError,
......
// 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/logging.h"
#include "chrome/test/chromedriver/capabilities.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/status.h"
Status CreateLoggers(const Capabilities& capabilities,
ScopedVector<DevToolsEventLogger>* out_loggers) {
if (capabilities.logging_prefs) {
ScopedVector<DevToolsEventLogger> loggers;
for (DictionaryValue::Iterator pref(*capabilities.logging_prefs);
!pref.IsAtEnd(); pref.Advance()) {
const std::string type = pref.key();
std::string level;
if (!pref.value().GetAsString(&level)) {
return Status(kUnknownError,
"logging level must be a string for log type: " + type);
}
if ("profiler" == type) {
std::vector<std::string> domains;
domains.push_back("Network");
domains.push_back("Page");
domains.push_back("Timeline");
loggers.push_back(new DevToolsEventLogger(type, domains, level));
} else {
return Status(kUnknownError, "unsupported log type: " + type);
}
// TODO(klm): Implement and add here the console logger.
}
out_loggers->swap(loggers);
}
return Status(kOk);
}
// Copyright (c) 2013 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_LOGGING_H_
#define CHROME_TEST_CHROMEDRIVER_LOGGING_H_
#include "base/memory/scoped_vector.h"
struct Capabilities;
class DevToolsEventLogger;
class Status;
Status CreateLoggers(const Capabilities& capabilities,
ScopedVector<DevToolsEventLogger>* out_loggers);
#endif // CHROME_TEST_CHROMEDRIVER_LOGGING_H_
// Copyright (c) 2013 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/logging.h"
#include "base/values.h"
#include "chrome/test/chromedriver/capabilities.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(Logging, CreatePerformanceLogger) {
Capabilities capabilities;
capabilities.logging_prefs.reset(new base::DictionaryValue());
capabilities.logging_prefs->SetString("profiler", "INFO");
ScopedVector<DevToolsEventLogger> loggers;
Status status = CreateLoggers(capabilities, &loggers);
ASSERT_TRUE(status.IsOk());
ASSERT_EQ(1u, loggers.size());
ASSERT_STREQ("profiler", loggers[0]->GetLogType().c_str());
}
TEST(Logging, InvalidLogType) {
Capabilities capabilities;
capabilities.logging_prefs.reset(new base::DictionaryValue());
capabilities.logging_prefs->SetString("gaga", "INFO");
ScopedVector<DevToolsEventLogger> loggers;
Status status = CreateLoggers(capabilities, &loggers);
EXPECT_FALSE(status.IsOk());
ASSERT_EQ(0u, loggers.size());
}
......@@ -159,6 +159,9 @@ int main(int argc, char *argv[]) {
false, // enable_thread_id
true, // enable_timestamp
false); // enable_tickcount
if (cmd_line->HasSwitch("verbose")) {
logging::SetMinLogLevel(logging::LOG_VERBOSE);
}
scoped_ptr<CommandExecutor> executor(new CommandExecutorImpl());
HttpHandler handler(executor.Pass(), HttpHandler::CreateCommandMap(),
......
......@@ -8,6 +8,7 @@
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/version.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
......
......@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "chrome/test/chromedriver/basic_types.h"
......@@ -21,6 +22,7 @@ class DictionaryValue;
}
class Chrome;
class DevToolsEventLogger;
class Status;
class WebView;
......@@ -61,6 +63,7 @@ struct Session {
int script_timeout;
std::string prompt_text;
scoped_ptr<Geoposition> overridden_geoposition;
ScopedVector<DevToolsEventLogger> devtools_event_loggers;
const scoped_ptr<base::DictionaryValue> capabilities;
private:
......
......@@ -17,6 +17,7 @@
#include "chrome/test/chromedriver/basic_types.h"
#include "chrome/test/chromedriver/chrome/automation_extension.h"
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/devtools_event_logger.h"
#include "chrome/test/chromedriver/chrome/geoposition.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
......@@ -472,3 +473,37 @@ Status ExecuteMaximizeWindow(
return extension->MaximizeWindow();
}
Status ExecuteGetAvailableLogTypes(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
scoped_ptr<ListValue> types(new base::ListValue());
for (ScopedVector<DevToolsEventLogger>::const_iterator logger =
session->devtools_event_loggers.begin();
logger != session->devtools_event_loggers.end(); ++logger) {
types->AppendString((*logger)->GetLogType());
}
value->reset(types.release());
return Status(kOk);
}
Status ExecuteGetLog(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string log_type;
if (!params.GetString("type", &log_type)) {
return Status(kUnknownError, "missing or invalid 'type'");
}
for (ScopedVector<DevToolsEventLogger>::const_iterator logger =
session->devtools_event_loggers.begin();
logger != session->devtools_event_loggers.end(); ++logger) {
if (log_type == (*logger)->GetLogType()) {
scoped_ptr<ListValue> log_entries = (*logger)->GetAndClearLogEntries();
value->reset(log_entries.release());
return Status(kOk);
}
}
return Status(kUnknownError, "log type '" + log_type + "' not found");
}
......@@ -159,4 +159,14 @@ Status ExecuteMaximizeWindow(
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
Status ExecuteGetAvailableLogTypes(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
Status ExecuteGetLog(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
#endif // CHROME_TEST_CHROMEDRIVER_SESSION_COMMANDS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment