Commit b70c577b authored by samuong@chromium.org's avatar samuong@chromium.org

[chromedriver] Add an error autoreporting feature that automatically raises...

[chromedriver] Add an error autoreporting feature that automatically raises errors from browser logs

BUG=chromedriver:543

Review URL: https://codereview.chromium.org/101203012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245432 0039d316-1c4b-4281-b951-d872f2087c98
parent 09b07927
...@@ -311,3 +311,9 @@ class ChromeDriver(object): ...@@ -311,3 +311,9 @@ class ChromeDriver(object):
def GetAvailableLogTypes(self): def GetAvailableLogTypes(self):
return self.ExecuteCommand(Command.GET_AVAILABLE_LOG_TYPES) return self.ExecuteCommand(Command.GET_AVAILABLE_LOG_TYPES)
def IsAutoReporting(self):
return self.ExecuteCommand(Command.IS_AUTO_REPORTING)
def SetAutoReporting(self, enabled):
self.ExecuteCommand(Command.SET_AUTO_REPORTING, {'enabled': enabled})
...@@ -133,6 +133,8 @@ class Command(object): ...@@ -133,6 +133,8 @@ class Command(object):
TOUCH_FLICK = (_Method.POST, '/session/:sessionId/touch/flick') TOUCH_FLICK = (_Method.POST, '/session/:sessionId/touch/flick')
GET_LOG = (_Method.POST, '/session/:sessionId/log') GET_LOG = (_Method.POST, '/session/:sessionId/log')
GET_AVAILABLE_LOG_TYPES = (_Method.GET, '/session/:sessionId/log/types') GET_AVAILABLE_LOG_TYPES = (_Method.GET, '/session/:sessionId/log/types')
IS_AUTO_REPORTING = (_Method.GET, '/session/:sessionId/autoreport')
SET_AUTO_REPORTING = (_Method.POST, '/session/:sessionId/autoreport')
GET_SESSION_LOGS = (_Method.POST, '/logs') GET_SESSION_LOGS = (_Method.POST, '/logs')
STATUS = (_Method.GET, '/status') STATUS = (_Method.GET, '/status')
......
...@@ -194,6 +194,12 @@ void ExecuteSessionCommandOnSessionThread( ...@@ -194,6 +194,12 @@ void ExecuteSessionCommandOnSessionThread(
<< (result.length() ? " " + result : ""); << (result.length() ? " " + result : "");
} }
if (status.IsOk() && session->auto_reporting_enabled) {
std::string message = session->GetFirstBrowserError();
if (!message.empty())
status = Status(kUnknownError, message);
}
cmd_task_runner->PostTask( cmd_task_runner->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(callback_on_cmd, status, base::Passed(&value), session->id)); base::Bind(callback_on_cmd, status, base::Passed(&value), session->id));
......
...@@ -150,6 +150,26 @@ scoped_ptr<base::ListValue> WebDriverLog::GetAndClearEntries() { ...@@ -150,6 +150,26 @@ scoped_ptr<base::ListValue> WebDriverLog::GetAndClearEntries() {
return ret.Pass(); return ret.Pass();
} }
std::string WebDriverLog::GetFirstErrorMessage() const {
for (base::ListValue::iterator it = entries_->begin();
it != entries_->end();
++it) {
base::DictionaryValue* log_entry = NULL;
(*it)->GetAsDictionary(&log_entry);
if (log_entry != NULL) {
std::string level;
if (log_entry->GetString("level", &level)) {
if (level == kLevelToName[Log::kError]) {
std::string message;
if (log_entry->GetString("message", &message))
return message;
}
}
}
}
return std::string();
}
void WebDriverLog::AddEntryTimestamped(const base::Time& timestamp, void WebDriverLog::AddEntryTimestamped(const base::Time& timestamp,
Log::Level level, Log::Level level,
const std::string& source, const std::string& source,
......
...@@ -39,6 +39,10 @@ class WebDriverLog : public Log { ...@@ -39,6 +39,10 @@ class WebDriverLog : public Log {
// creates and owns a new empty ListValue for further accumulation. // creates and owns a new empty ListValue for further accumulation.
scoped_ptr<base::ListValue> GetAndClearEntries(); scoped_ptr<base::ListValue> GetAndClearEntries();
// Finds the first error message in the log and returns it. If none exist,
// returns an empty string. Does not clear entries.
std::string GetFirstErrorMessage() const;
// Translates a Log entry level into a WebDriver level and stores the entry. // Translates a Log entry level into a WebDriver level and stores the entry.
virtual void AddEntryTimestamped(const base::Time& timestamp, virtual void AddEntryTimestamped(const base::Time& timestamp,
Level level, Level level,
......
...@@ -135,3 +135,19 @@ TEST(Logging, DefaultLogs) { ...@@ -135,3 +135,19 @@ TEST(Logging, DefaultLogs) {
ASSERT_EQ(1u, listeners.size()); ASSERT_EQ(1u, listeners.size());
ASSERT_EQ("browser", logs[0]->type()); ASSERT_EQ("browser", logs[0]->type());
} }
TEST(Logging, GetFirstErrorMessage) {
WebDriverLog log(WebDriverLog::kBrowserType, Log::kAll);
std::string entry;
entry = log.GetFirstErrorMessage();
ASSERT_TRUE(entry.empty());
log.AddEntry(Log::kInfo, "info message");
log.AddEntry(Log::kError, "first error message");
log.AddEntry(Log::kDebug, "debug message");
log.AddEntry(Log::kError, "second error message");
entry = log.GetFirstErrorMessage();
ASSERT_EQ("first error message", entry);
}
...@@ -523,6 +523,15 @@ HttpHandler::HttpHandler( ...@@ -523,6 +523,15 @@ HttpHandler::HttpHandler(
CommandMapping(kGet, CommandMapping(kGet,
"session/:sessionId/is_loading", "session/:sessionId/is_loading",
WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading))), WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading))),
CommandMapping(kGet,
"session/:sessionId/autoreport",
WrapToCommand("IsAutoReporting",
base::Bind(&ExecuteIsAutoReporting))),
CommandMapping(kPost,
"session/:sessionId/autoreport",
WrapToCommand(
"SetAutoReporting",
base::Bind(&ExecuteSetAutoReporting))),
}; };
command_map_.reset( command_map_.reset(
new CommandMap(commands, commands + arraysize(commands))); new CommandMap(commands, commands + arraysize(commands)));
......
...@@ -39,7 +39,8 @@ Session::Session(const std::string& id) ...@@ -39,7 +39,8 @@ Session::Session(const std::string& id)
force_devtools_screenshot(false), force_devtools_screenshot(false),
sticky_modifiers(0), sticky_modifiers(0),
mouse_position(0, 0), mouse_position(0, 0),
page_load_timeout(kDefaultPageLoadTimeout) {} page_load_timeout(kDefaultPageLoadTimeout),
auto_reporting_enabled(false) {}
Session::Session(const std::string& id, scoped_ptr<Chrome> chrome) Session::Session(const std::string& id, scoped_ptr<Chrome> chrome)
: id(id), : id(id),
...@@ -49,7 +50,8 @@ Session::Session(const std::string& id, scoped_ptr<Chrome> chrome) ...@@ -49,7 +50,8 @@ Session::Session(const std::string& id, scoped_ptr<Chrome> chrome)
chrome(chrome.Pass()), chrome(chrome.Pass()),
sticky_modifiers(0), sticky_modifiers(0),
mouse_position(0, 0), mouse_position(0, 0),
page_load_timeout(kDefaultPageLoadTimeout) {} page_load_timeout(kDefaultPageLoadTimeout),
auto_reporting_enabled(false) {}
Session::~Session() {} Session::~Session() {}
...@@ -93,6 +95,19 @@ std::vector<WebDriverLog*> Session::GetAllLogs() const { ...@@ -93,6 +95,19 @@ std::vector<WebDriverLog*> Session::GetAllLogs() const {
return logs; return logs;
} }
std::string Session::GetFirstBrowserError() const {
for (ScopedVector<WebDriverLog>::const_iterator it = devtools_logs.begin();
it != devtools_logs.end();
++it) {
if ((*it)->type() == WebDriverLog::kBrowserType) {
std::string message = (*it)->GetFirstErrorMessage();
if (!message.empty())
return message;
}
}
return std::string();
}
Session* GetThreadLocalSession() { Session* GetThreadLocalSession() {
return lazy_tls_session.Pointer()->Get(); return lazy_tls_session.Pointer()->Get();
} }
......
...@@ -49,6 +49,7 @@ struct Session { ...@@ -49,6 +49,7 @@ struct Session {
const std::string& chromedriver_frame_id); const std::string& chromedriver_frame_id);
std::string GetCurrentFrameId() const; std::string GetCurrentFrameId() const;
std::vector<WebDriverLog*> GetAllLogs() const; std::vector<WebDriverLog*> GetAllLogs() const;
std::string GetFirstBrowserError() const;
const std::string id; const std::string id;
bool quit; bool quit;
...@@ -72,6 +73,7 @@ struct Session { ...@@ -72,6 +73,7 @@ struct Session {
scoped_ptr<WebDriverLog> driver_log; scoped_ptr<WebDriverLog> driver_log;
base::ScopedTempDir temp_dir; base::ScopedTempDir temp_dir;
scoped_ptr<base::DictionaryValue> capabilities; scoped_ptr<base::DictionaryValue> capabilities;
bool auto_reporting_enabled;
}; };
Session* GetThreadLocalSession(); Session* GetThreadLocalSession();
......
...@@ -631,3 +631,22 @@ Status ExecuteUploadFile( ...@@ -631,3 +631,22 @@ Status ExecuteUploadFile(
value->reset(new base::StringValue(upload.value())); value->reset(new base::StringValue(upload.value()));
return Status(kOk); return Status(kOk);
} }
Status ExecuteIsAutoReporting(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
value->reset(new base::FundamentalValue(session->auto_reporting_enabled));
return Status(kOk);
}
Status ExecuteSetAutoReporting(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
bool enabled;
if (!params.GetBoolean("enabled", &enabled))
return Status(kUnknownError, "missing parameter 'enabled'");
session->auto_reporting_enabled = enabled;
return Status(kOk);
}
...@@ -158,4 +158,14 @@ Status ExecuteUploadFile( ...@@ -158,4 +158,14 @@ Status ExecuteUploadFile(
const base::DictionaryValue& params, const base::DictionaryValue& params,
scoped_ptr<base::Value>* value); scoped_ptr<base::Value>* value);
Status ExecuteIsAutoReporting(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
Status ExecuteSetAutoReporting(
Session* session,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
#endif // CHROME_TEST_CHROMEDRIVER_SESSION_COMMANDS_H_ #endif // CHROME_TEST_CHROMEDRIVER_SESSION_COMMANDS_H_
...@@ -111,3 +111,47 @@ TEST(SessionCommandsTest, QuitFails) { ...@@ -111,3 +111,47 @@ TEST(SessionCommandsTest, QuitFails) {
scoped_ptr<base::Value> value; scoped_ptr<base::Value> value;
ASSERT_EQ(kUnknownError, ExecuteQuit(false, &session, params, &value).code()); ASSERT_EQ(kUnknownError, ExecuteQuit(false, &session, params, &value).code());
} }
TEST(SessionCommandsTest, AutoReporting) {
DetachChrome* chrome = new DetachChrome();
Session session("id", scoped_ptr<Chrome>(chrome));
base::DictionaryValue params;
scoped_ptr<base::Value> value;
StatusCode status_code;
bool enabled;
// autoreporting should be disabled by default
status_code = ExecuteIsAutoReporting(&session, params, &value).code();
ASSERT_EQ(kOk, status_code);
ASSERT_FALSE(session.auto_reporting_enabled);
ASSERT_TRUE(value.get()->GetAsBoolean(&enabled));
ASSERT_FALSE(enabled);
// an error should be given if the |enabled| parameter is not set
status_code = ExecuteSetAutoReporting(&session, params, &value).code();
ASSERT_EQ(kUnknownError, status_code);
// try to enable autoreporting
params.SetBoolean("enabled", true);
status_code = ExecuteSetAutoReporting(&session, params, &value).code();
ASSERT_EQ(kOk, status_code);
ASSERT_TRUE(session.auto_reporting_enabled);
// check that autoreporting was enabled successfully
status_code = ExecuteIsAutoReporting(&session, params, &value).code();
ASSERT_EQ(kOk, status_code);
ASSERT_TRUE(value.get()->GetAsBoolean(&enabled));
ASSERT_TRUE(enabled);
// try to disable autoreporting
params.SetBoolean("enabled", false);
status_code = ExecuteSetAutoReporting(&session, params, &value).code();
ASSERT_EQ(kOk, status_code);
ASSERT_FALSE(session.auto_reporting_enabled);
// check that autoreporting was disabled successfully
status_code = ExecuteIsAutoReporting(&session, params, &value).code();
ASSERT_EQ(kOk, status_code);
ASSERT_TRUE(value.get()->GetAsBoolean(&enabled));
ASSERT_FALSE(enabled);
}
...@@ -632,6 +632,16 @@ class ChromeDriverTest(ChromeDriverBaseTest): ...@@ -632,6 +632,16 @@ class ChromeDriverTest(ChromeDriverBaseTest):
self.assertEquals(logs[0]['source'], 'network') self.assertEquals(logs[0]['source'], 'network')
self.assertEquals(logs[1]['source'], 'javascript') self.assertEquals(logs[1]['source'], 'javascript')
def testAutoReporting(self):
self.assertFalse(self._driver.IsAutoReporting())
self._driver.SetAutoReporting(True)
self.assertTrue(self._driver.IsAutoReporting())
url = self.GetHttpUrlForFile('/chromedriver/console_log.html')
self.assertRaisesRegexp(chromedriver.UnknownError,
'.*404.*',
self._driver.Load,
url)
def testContextMenuEventFired(self): def testContextMenuEventFired(self):
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html')) self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html'))
self._driver.MouseMoveTo(self._driver.FindElement('tagName', 'div')) self._driver.MouseMoveTo(self._driver.FindElement('tagName', 'div'))
......
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