Commit 509c7cc4 authored by Shengfa Lin's avatar Shengfa Lin Committed by Commit Bot

[chromedriver] Handle network error from page.navigate

If page.navigate has error text for network related error,
we would like to return unknown error status.

Bug: chromedriver:3488
Change-Id: Ia7ade877ea5bf43802b8587bc4d8f5687e8a6882
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2219110
Commit-Queue: Shengfa Lin <shengfa@google.com>
Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773170}
parent 662d7e36
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chrome/test/chromedriver/chrome/navigation_tracker.h" #include "chrome/test/chromedriver/chrome/navigation_tracker.h"
#include <unordered_map>
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/values.h" #include "base/values.h"
...@@ -32,6 +34,28 @@ Status MakeNavigationCheckFailedStatus(Status command_status) { ...@@ -32,6 +34,28 @@ Status MakeNavigationCheckFailedStatus(Status command_status) {
return Status(kUnknownError, "cannot determine loading status", return Status(kUnknownError, "cannot determine loading status",
command_status); command_status);
} }
std::unordered_map<std::string, int> error_codes({
#define NET_ERROR(label, value) {#label, value},
#include "net/base/net_error_list.h"
#undef NET_ERROR
});
const char kNetErrorStart[] = "net::ERR_";
bool isNetworkError(const std::string& errorText) {
if (!base::StartsWith(errorText, kNetErrorStart,
base::CompareCase::SENSITIVE))
return false;
auto it = error_codes.find(errorText.substr(strlen(kNetErrorStart)));
if (it == error_codes.end())
return false;
// According to comments in net/base/net_error_list.h
// range 100-199: Connection related errors
auto val = it->second;
return val <= -100 && val >= -199;
}
} // namespace } // namespace
...@@ -313,6 +337,12 @@ Status NavigationTracker::OnCommandSuccess( ...@@ -313,6 +337,12 @@ Status NavigationTracker::OnCommandSuccess(
const std::string& method, const std::string& method,
const base::DictionaryValue& result, const base::DictionaryValue& result,
const Timeout& command_timeout) { const Timeout& command_timeout) {
// Check if Page.navigate has any error from top frame
std::string error_text;
if (method == "Page.navigate" && result.GetString("errorText", &error_text) &&
isNetworkError(error_text))
return Status(kUnknownError, error_text);
// Check for start of navigation. In some case response to navigate is delayed // Check for start of navigation. In some case response to navigate is delayed
// until after the command has already timed out, in which case it has already // until after the command has already timed out, in which case it has already
// been cancelled or will be cancelled soon, and should be ignored. // been cancelled or will be cancelled soon, and should be ignored.
......
...@@ -513,6 +513,64 @@ TEST(NavigationTracker, OnSuccessfulNavigate) { ...@@ -513,6 +513,64 @@ TEST(NavigationTracker, OnSuccessfulNavigate) {
ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, false)); ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, false));
} }
TEST(NavigationTracker, OnNetworkErroredNavigate) {
BrowserInfo browser_info;
std::string version_string =
"{\"Browser\": \"Chrome/44.0.2403.125\","
" \"WebKit-Version\": \"537.36 (@199461)\"}";
ASSERT_TRUE(ParseBrowserInfo(version_string, &browser_info).IsOk());
base::DictionaryValue dict;
std::unique_ptr<DevToolsClient> client_uptr =
std::make_unique<DeterminingLoadStateDevToolsClient>(
false, true, std::string(), &dict);
DevToolsClient* client_ptr = client_uptr.get();
JavaScriptDialogManager dialog_manager(client_ptr, &browser_info);
EvaluateScriptWebView web_view(kOk);
NavigationTracker tracker(client_ptr, NavigationTracker::kNotLoading,
&web_view, &browser_info, &dialog_manager);
base::DictionaryValue params;
base::DictionaryValue result;
result.SetString("frameId", client_ptr->GetId());
result.SetString("errorText", "net::ERR_PROXY_CONNECTION_FAILED");
web_view.nextEvaluateScript("loading", kOk);
ASSERT_NE(
kOk,
tracker.OnCommandSuccess(client_ptr, "Page.navigate", result, Timeout())
.code());
ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, false));
}
TEST(NavigationTracker, OnNonNetworkErroredNavigate) {
BrowserInfo browser_info;
std::string version_string =
"{\"Browser\": \"Chrome/44.0.2403.125\","
" \"WebKit-Version\": \"537.36 (@199461)\"}";
ASSERT_TRUE(ParseBrowserInfo(version_string, &browser_info).IsOk());
base::DictionaryValue dict;
std::unique_ptr<DevToolsClient> client_uptr =
std::make_unique<DeterminingLoadStateDevToolsClient>(
false, true, std::string(), &dict);
DevToolsClient* client_ptr = client_uptr.get();
JavaScriptDialogManager dialog_manager(client_ptr, &browser_info);
EvaluateScriptWebView web_view(kOk);
NavigationTracker tracker(client_ptr, NavigationTracker::kNotLoading,
&web_view, &browser_info, &dialog_manager);
base::DictionaryValue params;
base::DictionaryValue result;
result.SetString("frameId", client_ptr->GetId());
result.SetString("errorText", "net::ERR_CERT_COMMON_NAME_INVALID");
web_view.nextEvaluateScript("loading", kOk);
tracker.OnCommandSuccess(client_ptr, "Page.navigate", result, Timeout());
ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, true));
web_view.nextEvaluateScript("complete", kOk);
tracker.OnEvent(client_ptr, "Page.loadEventFired", params);
ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, false));
}
namespace { namespace {
class TargetClosedDevToolsClient : public StubDevToolsClient { class TargetClosedDevToolsClient : public StubDevToolsClient {
......
...@@ -1617,7 +1617,9 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer): ...@@ -1617,7 +1617,9 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer):
# A workaround for crbug.com/177511; when setting offline, the throughputs # A workaround for crbug.com/177511; when setting offline, the throughputs
# must be 0. # must be 0.
self._driver.SetNetworkConditions(0, 0, 0, offline=True) self._driver.SetNetworkConditions(0, 0, 0, offline=True)
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) self.assertRaises(chromedriver.ChromeDriverException,
self._driver.Load,
self.GetHttpUrlForFile('/chromedriver/page_test.html'))
# The "X is not available" title is set after the page load event fires, so # The "X is not available" title is set after the page load event fires, so
# we have to explicitly wait for this to change. We can't rely on the # we have to explicitly wait for this to change. We can't rely on the
# navigation tracker to block the call to Load() above. # navigation tracker to block the call to Load() above.
...@@ -1945,7 +1947,7 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer): ...@@ -1945,7 +1947,7 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer):
# https://bugs.chromium.org/p/chromedriver/issues/detail?id=1272). RFC 6761 # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1272). RFC 6761
# requires domain registrars to keep 'invalid.' unregistered (see # requires domain registrars to keep 'invalid.' unregistered (see
# https://tools.ietf.org/html/rfc6761#section-6.4). # https://tools.ietf.org/html/rfc6761#section-6.4).
self._driver.Load('http://invalid./') self.assertRaises(chromedriver.ChromeDriverException, self._driver.Load, 'http://invalid./')
self.assertEquals('http://invalid./', self._driver.GetCurrentUrl()) self.assertEquals('http://invalid./', self._driver.GetCurrentUrl())
def testCanClickAlertInIframes(self): def testCanClickAlertInIframes(self):
......
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