Chromium Code Reviews| Index: chrome/test/chromedriver/chrome_impl.cc |
| diff --git a/chrome/test/chromedriver/chrome_impl.cc b/chrome/test/chromedriver/chrome_impl.cc |
| index 78038c3112222a2cdf82545123845a681cd769d6..8b665cccd840a70d138c51dc6643b2e6c70c0311 100644 |
| --- a/chrome/test/chromedriver/chrome_impl.cc |
| +++ b/chrome/test/chromedriver/chrome_impl.cc |
| @@ -23,21 +23,30 @@ |
| namespace { |
| +typedef base::Callback<Status(base::ListValue*)> ParserFunc; |
| Status FetchPagesInfo(URLRequestContextGetter* context_getter, |
| int port, |
| - std::list<std::string>* page_ids) { |
| + const ParserFunc& parser) { |
|
kkania
2013/02/22 01:35:24
i think this might be simpler to understand if ins
chrisgao (Use stgao instead)
2013/02/27 19:29:44
Done.
|
| 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); |
| + scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
| + if (!value.get()) |
| + return Status(kUnknownError, "DevTools returned invalid JSON"); |
| + base::ListValue* list; |
| + if (!value->GetAsList(&list)) |
| + return Status(kUnknownError, "DevTools did not return list"); |
| + |
| + return parser.Run(list); |
| } |
| 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); |
| + Status status = FetchPagesInfo( |
| + context_getter, port, base::Bind(internal::ParsePagesInfo, &ids)); |
| if (status.IsError()) |
| return status; |
| if (std::find(ids.begin(), ids.end(), web_view_id) == ids.end()) |
| @@ -57,7 +66,8 @@ Status CloseWebView(URLRequestContextGetter* context_getter, |
| base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20); |
| while (base::Time::Now() < deadline) { |
| ids.clear(); |
| - status = FetchPagesInfo(context_getter, port, &ids); |
| + status = FetchPagesInfo( |
| + context_getter, port, base::Bind(internal::ParsePagesInfo, &ids)); |
| if (is_last_web_view && status.code() == kChromeNotReachable) |
| return Status(kOk); // Closing the last web view leads chrome to quit. |
| if (status.IsError()) |
| @@ -70,6 +80,83 @@ Status CloseWebView(URLRequestContextGetter* context_getter, |
| return Status(kUnknownError, "failed to close window in 20 seconds"); |
| } |
| +Status FakeCloseWebView() { |
| + return Status(kUnknownError, |
| + "built-in DevTools frontend should be closed by Javascript"); |
| +} |
| + |
| +Status FakeCloseDevToolsFrontend() { |
| + return Status(kUnknownError, |
| + "built-in DevTools frontend should not try to close others"); |
| +} |
| + |
| +Status CloseDevToolsFrontend(ChromeImpl* chrome, |
| + const SyncWebSocketFactory& socket_factory, |
| + URLRequestContextGetter* context_getter, |
| + int port, |
| + const std::string& page_id) { |
| + std::list<std::string> page_ids; // DevTools opened in a separate page. |
| + std::list<std::string> frontend_ids; // In-page DevTools frontend. |
|
kkania
2013/02/22 01:35:24
the naming here is a bit confusing. how about call
chrisgao (Use stgao instead)
2013/02/27 19:29:44
Good suggestion.
|
| + |
| + Status status = FetchPagesInfo( |
| + context_getter, port, |
| + base::Bind(internal::ParseDevToolsInfo, &page_ids, &frontend_ids)); |
| + if (status.IsError()) |
| + return status; |
| + |
| + if (!page_ids.empty()) { |
| + // Close DevTools page in the same way as a normal web view by json/close. |
| + std::list<WebView*> web_views; |
| + status = chrome->GetWebViews(&web_views); |
| + if (status.IsError()) |
| + return status; |
| + for (std::list<WebView*>::const_iterator it = web_views.begin(); |
| + it != web_views.end(); ++it) { |
| + if (std::find(page_ids.begin(), page_ids.end(), (*it)->GetId()) |
| + != page_ids.end()) { |
| + status = (*it)->Close(); |
| + if (status.IsError()) |
| + return status; |
| + } |
| + } |
| + } |
| + |
| + // Close in-page DevTools frontend by Javascript. |
| + for (std::list<std::string>::const_iterator it = frontend_ids.begin(); |
| + it != 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))); |
| + |
| + 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. |
|
kkania
2013/02/22 01:35:24
disconnected, D->d
chrisgao (Use stgao instead)
2013/02/27 19:29:44
Done.
|
| + 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 has_debugger_url = false; |
| + base::Callback<Status(base::ListValue*)> checker = |
| + base::Bind(&internal::CheckPageDebuggerUrl, page_id, &has_debugger_url); |
| + while (base::Time::Now() < deadline) { |
| + status = FetchPagesInfo(context_getter, port, checker); |
| + if (status.IsError()) |
| + return status; |
| + if (has_debugger_url) |
| + return Status(kOk); |
| + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); |
| + } |
| + |
| + return Status(kUnknownError, "failed to close DevTools frontend"); |
| +} |
| + |
| } // namespace |
| ChromeImpl::ChromeImpl(URLRequestContextGetter* context_getter, |
| @@ -85,7 +172,8 @@ ChromeImpl::~ChromeImpl() { |
| Status ChromeImpl::GetWebViews(std::list<WebView*>* web_views) { |
| std::list<std::string> ids; |
| - Status status = FetchPagesInfo(context_getter_, port_, &ids); |
| + Status status = FetchPagesInfo( |
| + context_getter_, port_, base::Bind(internal::ParsePagesInfo, &ids)); |
| if (status.IsError()) |
| return status; |
| @@ -100,9 +188,14 @@ Status ChromeImpl::GetWebViews(std::list<WebView*>* web_views) { |
| std::string ws_url = base::StringPrintf( |
| "ws://127.0.0.1:%d/devtools/page/%s", port_, it->c_str()); |
| + DevToolsClientImpl::FrontendCloserFunc frontend_closer_func = base::Bind( |
| + &CloseDevToolsFrontend, this, socket_factory_, |
| + context_getter_, port_, *it); |
| web_view_map_[*it] = make_linked_ptr(new WebViewImpl( |
| - *it, new DevToolsClientImpl(socket_factory_, ws_url), |
| - this, base::Bind(&CloseWebView, context_getter_, port_, *it))); |
| + *it, |
| + new DevToolsClientImpl(socket_factory_, ws_url, frontend_closer_func), |
| + this, |
| + base::Bind(&CloseWebView, context_getter_, port_, *it))); |
| internal_web_views.push_back(web_view_map_[*it].get()); |
| } |
| @@ -118,7 +211,8 @@ Status ChromeImpl::Init() { |
| base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20); |
| std::list<std::string> page_ids; |
| while (base::Time::Now() < deadline) { |
| - FetchPagesInfo(context_getter_, port_, &page_ids); |
| + FetchPagesInfo(context_getter_, port_, |
| + base::Bind(internal::ParsePagesInfo, &page_ids)); |
| if (page_ids.empty()) |
| base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); |
| else |
| @@ -136,19 +230,12 @@ int ChromeImpl::GetPort() const { |
| namespace internal { |
| -Status ParsePagesInfo(const std::string& data, |
| - std::list<std::string>* page_ids) { |
| - scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
| - if (!value.get()) |
| - return Status(kUnknownError, "DevTools returned invalid JSON"); |
| - base::ListValue* list; |
| - if (!value->GetAsList(&list)) |
| - return Status(kUnknownError, "DevTools did not return list"); |
| - |
| +Status ParsePagesInfo(std::list<std::string>* page_ids, |
| + base::ListValue* page_info_list) { |
| std::list<std::string> ids; |
| - for (size_t i = 0; i < list->GetSize(); ++i) { |
| + for (size_t i = 0; i < page_info_list->GetSize(); ++i) { |
| base::DictionaryValue* info; |
| - if (!list->GetDictionary(i, &info)) |
| + if (!page_info_list->GetDictionary(i, &info)) |
| return Status(kUnknownError, "DevTools contains non-dictionary item"); |
| std::string type; |
| if (!info->GetString("type", &type)) |
| @@ -164,4 +251,58 @@ Status ParsePagesInfo(const std::string& data, |
| return Status(kOk); |
| } |
| +Status ParseDevToolsInfo(std::list<std::string>* page_devtools_ids, |
| + std::list<std::string>* frontend_devtools_ids, |
| + base::ListValue* page_info_list) { |
| + std::list<std::string> page_devtools_ids_tmp; |
| + std::list<std::string> frontend_devtools_ids_tmp; |
| + for (size_t i = 0; i < page_info_list->GetSize(); ++i) { |
| + base::DictionaryValue* info; |
| + if (!page_info_list->GetDictionary(i, &info)) |
| + return Status(kUnknownError, "DevTools contains non-dictionary item"); |
| + std::string url; |
| + if (!info->GetString("url", &url)) |
| + return Status(kUnknownError, "DevTools did not include url"); |
| + if (url.find("chrome-devtools://") != 0u) |
| + continue; |
| + std::string id; |
| + if (!info->GetString("id", &id)) |
| + return Status(kUnknownError, "DevTools did not include id"); |
| + std::string type; |
| + if (!info->GetString("type", &type)) |
| + return Status(kUnknownError, "DevTools did not include type"); |
| + if (type == "page") |
| + page_devtools_ids_tmp.push_back(id); |
| + else if (type == "other") |
| + frontend_devtools_ids_tmp.push_back(id); |
| + else |
| + return Status(kUnknownError, "unknown type of devtools:" + type); |
| + } |
| + |
| + page_devtools_ids->swap(page_devtools_ids_tmp); |
| + frontend_devtools_ids->swap(frontend_devtools_ids_tmp); |
| + return Status(kOk); |
| +} |
| + |
| +Status CheckPageDebuggerUrl(const std::string& page_id, |
| + bool* has_debugger_url, |
| + base::ListValue* page_info_list) { |
| + std::list<std::string> ids; |
| + for (size_t i = 0; i < page_info_list->GetSize(); ++i) { |
| + base::DictionaryValue* info; |
| + if (!page_info_list->GetDictionary(i, &info)) |
| + return Status(kUnknownError, "DevTools contains non-dictionary item"); |
| + std::string id; |
| + if (!info->GetString("id", &id)) |
| + return Status(kUnknownError, "DevTools did not include id"); |
| + if (id == page_id) { |
| + std::string debugger_url; |
| + *has_debugger_url = info->GetString("webSocketDebuggerUrl", &debugger_url) |
| + && !debugger_url.empty(); |
| + return Status(kOk); |
| + } |
| + } |
| + return Status(kUnknownError, "page closed while closing devtools frontend"); |
| +} |
| + |
| } // namespace internal |