Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7830)

Unified Diff: chrome/test/chromedriver/chrome_impl.cc

Issue 12321057: [chromedriver] Implement reconnection to DevTools. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix nits. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/test/chromedriver/chrome_impl.cc
diff --git a/chrome/test/chromedriver/chrome_impl.cc b/chrome/test/chromedriver/chrome_impl.cc
index d91d7603bc80e24783992b66baa90949491dab3a..8867657017294f28d91faebaf9f2bba5fb5354de 100644
--- a/chrome/test/chromedriver/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome_impl.cc
@@ -24,27 +24,40 @@
namespace {
+typedef std::list<internal::WebViewInfo> WebViewInfoList;
+
Status FetchPagesInfo(URLRequestContextGetter* context_getter,
kkania 2013/03/04 23:33:57 this naming is no longer consistent since we've ch
chrisgao (Use stgao instead) 2013/03/05 06:58:17 Done. Changed name of function.
int port,
- std::list<std::string>* page_ids) {
+ WebViewInfoList* web_view_info_list) {
std::string url = base::StringPrintf("http://127.0.0.1:%d/json", port);
std::string data;
if (!FetchUrl(GURL(url), context_getter, &data))
return Status(kChromeNotReachable);
- return internal::ParsePagesInfo(data, page_ids);
+
+ return ParsePagesInfo(data, web_view_info_list);
+}
+
+bool WebViewExist(const std::string& web_view_id,
kkania 2013/03/04 23:33:57 convention is to name this as DoesWebViewExist
chrisgao (Use stgao instead) 2013/03/05 06:58:17 Done.
+ const WebViewInfoList& info_list) {
+ for (WebViewInfoList::const_iterator it = info_list.begin();
+ it != info_list.end(); ++it) {
+ if (it->id == web_view_id)
+ return true;
+ }
+ return false;
}
Status CloseWebView(URLRequestContextGetter* context_getter,
int port,
const std::string& web_view_id) {
- std::list<std::string> ids;
- Status status = FetchPagesInfo(context_getter, port, &ids);
+ WebViewInfoList web_view_info_list;
+ Status status = FetchPagesInfo(context_getter, port, &web_view_info_list);
if (status.IsError())
return status;
- if (std::find(ids.begin(), ids.end(), web_view_id) == ids.end())
+ if (!WebViewExist(web_view_id, web_view_info_list))
return Status(kOk);
- bool is_last_web_view = ids.size() == 1;
+ bool is_last_web_view = web_view_info_list.size() == 1u;
std::string url = base::StringPrintf(
"http://127.0.0.1:%d/json/close/%s", port, web_view_id.c_str());
@@ -57,13 +70,13 @@ Status CloseWebView(URLRequestContextGetter* context_getter,
// Wait for the target window to be completely closed.
base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20);
while (base::Time::Now() < deadline) {
- ids.clear();
- status = FetchPagesInfo(context_getter, port, &ids);
+ web_view_info_list.clear();
+ status = FetchPagesInfo(context_getter, port, &web_view_info_list);
if (is_last_web_view && status.code() == kChromeNotReachable)
return Status(kOk); // Closing the last web view leads chrome to quit.
if (status.IsError())
return status;
- if (std::find(ids.begin(), ids.end(), web_view_id) == ids.end())
+ if (!WebViewExist(web_view_id, web_view_info_list))
return Status(kOk);
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
}
@@ -71,6 +84,101 @@ Status CloseWebView(URLRequestContextGetter* context_getter,
return Status(kUnknownError, "failed to close window in 20 seconds");
}
+Status FakeCloseWebView() {
+ // This is for the docked DevTools frontend only.
+ return Status(kUnknownError,
+ "docked DevTools frontend should be closed by Javascript");
+}
+
+Status FakeCloseDevToolsFrontend() {
+ // This is for the docked DevTools frontend only.
+ return Status(kOk);
+}
+
+Status CloseDevToolsFrontend(ChromeImpl* chrome,
+ const SyncWebSocketFactory& socket_factory,
+ URLRequestContextGetter* context_getter,
+ int port,
+ const std::string& web_view_id) {
+ WebViewInfoList web_view_info_list;
+ Status status = FetchPagesInfo(context_getter, port, &web_view_info_list);
+ if (status.IsError())
+ return status;
+
+ std::list<std::string> tab_frontend_ids;
+ std::list<std::string> docked_frontend_ids;
+ // Filter out DevTools frontend.
+ for (WebViewInfoList::const_iterator it = web_view_info_list.begin();
+ it != web_view_info_list.end(); ++it) {
+ if (it->url.find("chrome-devtools://") == 0u) {
+ if (it->type == internal::WebViewInfo::kPage)
+ tab_frontend_ids.push_back(it->id);
+ else if (it->type == internal::WebViewInfo::kOther)
+ docked_frontend_ids.push_back(it->id);
+ else
+ return Status(kUnknownError, "unknown type of DevTools frontend");
+ }
+ }
+
+ // Close tab DevTools frontend as if closing a normal web view.
+ for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
+ it != tab_frontend_ids.end(); ++it) {
+ status = CloseWebView(context_getter, port, *it);
+ if (status.IsError())
+ return status;
+ }
+
+ // Close docked DevTools frontend by Javascript.
+ for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
+ it != docked_frontend_ids.end(); ++it) {
+ std::string ws_url = base::StringPrintf(
+ "ws://127.0.0.1:%d/devtools/page/%s", port, it->c_str());
+ scoped_ptr<WebViewImpl> web_view(new WebViewImpl(
+ *it,
+ new DevToolsClientImpl(socket_factory, ws_url,
+ base::Bind(&FakeCloseDevToolsFrontend)),
+ chrome, base::Bind(&FakeCloseWebView)));
+
+ status = web_view->EnsureAlive();
+ if (status.IsError())
+ return status;
+
+ scoped_ptr<base::Value> result;
+ status = web_view->EvaluateScript(
+ "", "document.getElementById('close-button-right').click();", &result);
+ // Ignore disconnected error, because the DevTools frontend is closed.
+ if (status.IsError() && status.code() != kDisconnected)
+ return status;
+ }
+
+ // Wait until DevTools UI disconnects from the given web view.
+ base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20);
+ bool web_view_still_open = false;
+ while (base::Time::Now() < deadline) {
+ web_view_info_list.clear();
+ status = FetchPagesInfo(context_getter, port, &web_view_info_list);
+ if (status.IsError())
+ return status;
+
+ web_view_still_open = false;
+ for (WebViewInfoList::const_iterator it = web_view_info_list.begin();
+ it != web_view_info_list.end(); ++it) {
+ if (it->id == web_view_id) {
+ if (!it->debugger_url.empty())
+ return Status(kOk);
+ web_view_still_open = true;
+ break;
+ }
+ }
+ if (!web_view_still_open)
+ return Status(kUnknownError, "window closed while closing devtools");
+
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
+ }
+
+ return Status(kUnknownError, "failed to close DevTools frontend");
+}
+
} // namespace
ChromeImpl::ChromeImpl(URLRequestContextGetter* context_getter,
@@ -85,26 +193,31 @@ ChromeImpl::~ChromeImpl() {
}
Status ChromeImpl::GetWebViews(std::list<WebView*>* web_views) {
- std::list<std::string> ids;
- Status status = FetchPagesInfo(context_getter_, port_, &ids);
+ WebViewInfoList web_view_info_list;
+ Status status = FetchPagesInfo(context_getter_, port_, &web_view_info_list);
if (status.IsError())
return status;
std::list<WebView*> internal_web_views;
- for (std::list<std::string>::const_iterator it = ids.begin();
- it != ids.end(); ++it) {
- WebViewMap::const_iterator found = web_view_map_.find(*it);
+ for (WebViewInfoList::const_iterator it = web_view_info_list.begin();
+ it != web_view_info_list.end(); ++it) {
+ WebViewMap::const_iterator found = web_view_map_.find(it->id);
if (found != web_view_map_.end()) {
internal_web_views.push_back(found->second.get());
continue;
}
std::string ws_url = base::StringPrintf(
- "ws://127.0.0.1:%d/devtools/page/%s", port_, it->c_str());
- web_view_map_[*it] = make_linked_ptr(new WebViewImpl(
- *it, new DevToolsClientImpl(socket_factory_, ws_url),
- this, base::Bind(&CloseWebView, context_getter_, port_, *it)));
- internal_web_views.push_back(web_view_map_[*it].get());
+ "ws://127.0.0.1:%d/devtools/page/%s", port_, it->id.c_str());
+ DevToolsClientImpl::FrontendCloserFunc frontend_closer_func = base::Bind(
+ &CloseDevToolsFrontend, this, socket_factory_,
+ context_getter_, port_, it->id);
+ web_view_map_[it->id] = make_linked_ptr(new WebViewImpl(
+ it->id,
+ new DevToolsClientImpl(socket_factory_, ws_url, frontend_closer_func),
+ this,
+ base::Bind(&CloseWebView, context_getter_, port_, it->id)));
+ internal_web_views.push_back(web_view_map_[it->id].get());
}
web_views->swap(internal_web_views);
@@ -149,18 +262,15 @@ void ChromeImpl::OnWebViewClose(WebView* web_view) {
Status ChromeImpl::Init() {
base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20);
- std::list<std::string> page_ids;
+ WebViewInfoList web_view_info_list;
while (base::Time::Now() < deadline) {
- FetchPagesInfo(context_getter_, port_, &page_ids);
- if (page_ids.empty())
+ FetchPagesInfo(context_getter_, port_, &web_view_info_list);
+ if (web_view_info_list.empty())
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
else
- break;
+ return Status(kOk);
}
- if (page_ids.empty())
- return Status(kUnknownError, "unable to discover open pages");
-
- return Status(kOk);
+ return Status(kUnknownError, "unable to discover open pages");
}
int ChromeImpl::GetPort() const {
@@ -187,8 +297,14 @@ Status ChromeImpl::GetDialogManagerForOpenDialog(
namespace internal {
+WebViewInfo::WebViewInfo(const std::string& id,
+ const std::string& debugger_url,
+ const std::string& url,
+ Type type)
+ : id(id), debugger_url(debugger_url), url(url), type(type) {}
+
Status ParsePagesInfo(const std::string& data,
- std::list<std::string>* page_ids) {
+ std::list<WebViewInfo>* web_view_info_list) {
scoped_ptr<base::Value> value(base::JSONReader::Read(data));
if (!value.get())
return Status(kUnknownError, "DevTools returned invalid JSON");
@@ -196,22 +312,32 @@ Status ParsePagesInfo(const std::string& data,
if (!value->GetAsList(&list))
return Status(kUnknownError, "DevTools did not return list");
- std::list<std::string> ids;
+ std::list<WebViewInfo> web_view_info_list_tmp;
for (size_t i = 0; i < list->GetSize(); ++i) {
base::DictionaryValue* info;
if (!list->GetDictionary(i, &info))
return Status(kUnknownError, "DevTools contains non-dictionary item");
- std::string type;
- if (!info->GetString("type", &type))
- return Status(kUnknownError, "DevTools did not include type");
- if (type != "page")
- continue;
std::string id;
if (!info->GetString("id", &id))
return Status(kUnknownError, "DevTools did not include id");
- ids.push_back(id);
+ std::string type;
+ if (!info->GetString("type", &type))
+ return Status(kUnknownError, "DevTools did not include type");
+ std::string url;
+ if (!info->GetString("url", &url))
+ return Status(kUnknownError, "DevTools did not include url");
+ std::string debugger_url;
+ info->GetString("webSocketDebuggerUrl", &debugger_url);
+ if (type == "page")
+ web_view_info_list_tmp.push_back(
+ WebViewInfo(id, debugger_url, url, internal::WebViewInfo::kPage));
+ else if (type == "other")
+ web_view_info_list_tmp.push_back(
+ WebViewInfo(id, debugger_url, url, internal::WebViewInfo::kOther));
+ else
+ return Status(kUnknownError, "DevTools returned unknown type:" + type);
}
- page_ids->swap(ids);
+ web_view_info_list->swap(web_view_info_list_tmp);
return Status(kOk);
}

Powered by Google App Engine
This is Rietveld 408576698