1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/io_thread.h"
16 #include "chrome/browser/net/chrome_net_log.h"
17 #include "chrome/browser/prerender/prerender_manager.h"
18 #include "chrome/browser/prerender/prerender_manager_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_ui_message_handler.h"
28 #include "net/base/address_list.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/net_log.h"
31 #include "net/base/net_log_logger.h"
32 #include "net/dns/host_cache.h"
33 #include "net/dns/host_resolver.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "net/http/http_network_session.h"
36 #include "net/http/http_pipelined_host_capability.h"
37 #include "net/http/http_transaction_factory.h"
38 #include "net/url_request/url_request_context.h"
39 #include "net/url_request/url_request_context_getter.h"
40 #include "testing/gtest/include/gtest/gtest.h"
43 using content::BrowserThread
;
44 using content::WebUIMessageHandler
;
48 // Called on IO thread. Adds an entry to the cache for the specified hostname.
49 // Either |net_error| must be net::OK, or |address| must be NULL.
50 void AddCacheEntryOnIOThread(net::URLRequestContextGetter
* context_getter
,
51 const std::string
& hostname
,
52 const std::string
& ip_literal
,
54 int expire_days_from_now
) {
55 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
56 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
57 net::HostCache
* cache
= context
->host_resolver()->GetHostCache();
60 net::HostCache::Key
key(hostname
, net::ADDRESS_FAMILY_UNSPECIFIED
, 0);
61 base::TimeDelta ttl
= base::TimeDelta::FromDays(expire_days_from_now
);
63 net::AddressList address_list
;
64 if (net_error
== net::OK
) {
65 // If |net_error| does not indicate an error, convert |ip_literal| to a
66 // net::AddressList, so it can be used with the cache.
67 int rv
= net::ParseAddressList(ip_literal
, hostname
, &address_list
);
68 ASSERT_EQ(net::OK
, rv
);
70 ASSERT_TRUE(ip_literal
.empty());
73 // Add entry to the cache.
74 cache
->Set(net::HostCache::Key(hostname
, net::ADDRESS_FAMILY_UNSPECIFIED
, 0),
75 net::HostCache::Entry(net_error
, address_list
),
76 base::TimeTicks::Now(),
80 // Called on IO thread. Adds an entry to the list of known HTTP pipelining
82 void AddDummyHttpPipelineFeedbackOnIOThread(
83 net::URLRequestContextGetter
* context_getter
,
84 const std::string
& hostname
,
86 net::HttpPipelinedHostCapability capability
) {
87 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
88 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
89 net::HttpNetworkSession
* http_network_session
=
90 context
->http_transaction_factory()->GetSession();
91 base::WeakPtr
<net::HttpServerProperties
> http_server_properties
=
92 http_network_session
->http_server_properties();
93 net::HostPortPair
origin(hostname
, port
);
94 http_server_properties
->SetPipelineCapability(origin
, capability
);
97 // Called on IO thread. Adds an entry to the list of known HTTP pipelining
99 void EnableHttpPipeliningOnIOThread(
100 net::URLRequestContextGetter
* context_getter
, bool enable
) {
101 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
102 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
103 net::HttpNetworkSession
* http_network_session
=
104 context
->http_transaction_factory()->GetSession();
105 http_network_session
->set_http_pipelining_enabled(enable
);
110 ////////////////////////////////////////////////////////////////////////////////
111 // NetInternalsTest::MessageHandler
112 ////////////////////////////////////////////////////////////////////////////////
114 // Class to handle messages from the renderer needed by certain tests.
115 class NetInternalsTest::MessageHandler
: public content::WebUIMessageHandler
{
117 explicit MessageHandler(NetInternalsTest
* net_internals_test
);
120 virtual void RegisterMessages() OVERRIDE
;
122 // Runs NetInternalsTest.callback with the given value.
123 void RunJavascriptCallback(base::Value
* value
);
125 // Takes a string and provides the corresponding URL from the test server,
126 // which must already have been started.
127 void GetTestServerURL(const base::ListValue
* list_value
);
129 // Called on UI thread. Adds an entry to the cache for the specified
130 // hostname by posting a task to the IO thread. Takes the host name,
131 // ip address, net error code, and expiration time in days from now
132 // as parameters. If the error code indicates failure, the ip address
133 // must be an empty string.
134 void AddCacheEntry(const base::ListValue
* list_value
);
136 // Opens the given URL in a new tab.
137 void LoadPage(const base::ListValue
* list_value
);
139 // Opens a page in a new tab that prerenders the given URL.
140 void PrerenderPage(const base::ListValue
* list_value
);
142 // Navigates to the prerender in the background tab. This assumes that
143 // there is a "Click()" function in the background tab which will navigate
144 // there, and that the background tab exists at slot 1.
145 void NavigateToPrerender(const base::ListValue
* list_value
);
147 // Creates an incognito browser. Once creation is complete, passes a
148 // message to the Javascript test harness.
149 void CreateIncognitoBrowser(const base::ListValue
* list_value
);
151 // Closes an incognito browser created with CreateIncognitoBrowser.
152 void CloseIncognitoBrowser(const base::ListValue
* list_value
);
154 // Takes in a boolean and enables/disabled HTTP pipelining accordingly.
155 void EnableHttpPipelining(const base::ListValue
* list_value
);
157 // Called on UI thread. Adds an entry to the list of known HTTP pipelining
159 void AddDummyHttpPipelineFeedback(const base::ListValue
* list_value
);
161 // Creates a simple log with a NetLogLogger, and returns it to the
162 // Javascript callback.
163 void GetNetLogLoggerLog(const base::ListValue
* list_value
);
165 Browser
* browser() { return net_internals_test_
->browser(); }
167 NetInternalsTest
* net_internals_test_
;
168 Browser
* incognito_browser_
;
170 DISALLOW_COPY_AND_ASSIGN(MessageHandler
);
173 NetInternalsTest::MessageHandler::MessageHandler(
174 NetInternalsTest
* net_internals_test
)
175 : net_internals_test_(net_internals_test
),
176 incognito_browser_(NULL
) {
179 void NetInternalsTest::MessageHandler::RegisterMessages() {
180 web_ui()->RegisterMessageCallback("getTestServerURL",
181 base::Bind(&NetInternalsTest::MessageHandler::GetTestServerURL
,
182 base::Unretained(this)));
183 web_ui()->RegisterMessageCallback("addCacheEntry",
184 base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry
,
185 base::Unretained(this)));
186 web_ui()->RegisterMessageCallback("loadPage",
187 base::Bind(&NetInternalsTest::MessageHandler::LoadPage
,
188 base::Unretained(this)));
189 web_ui()->RegisterMessageCallback("prerenderPage",
190 base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage
,
191 base::Unretained(this)));
192 web_ui()->RegisterMessageCallback("navigateToPrerender",
193 base::Bind(&NetInternalsTest::MessageHandler::NavigateToPrerender
,
194 base::Unretained(this)));
195 web_ui()->RegisterMessageCallback("createIncognitoBrowser",
196 base::Bind(&NetInternalsTest::MessageHandler::CreateIncognitoBrowser
,
197 base::Unretained(this)));
198 web_ui()->RegisterMessageCallback("closeIncognitoBrowser",
199 base::Bind(&NetInternalsTest::MessageHandler::CloseIncognitoBrowser
,
200 base::Unretained(this)));
201 web_ui()->RegisterMessageCallback("enableHttpPipelining",
202 base::Bind(&NetInternalsTest::MessageHandler::EnableHttpPipelining
,
203 base::Unretained(this)));
204 web_ui()->RegisterMessageCallback("addDummyHttpPipelineFeedback",
206 &NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback
,
207 base::Unretained(this)));
208 web_ui()->RegisterMessageCallback("getNetLogLoggerLog",
210 &NetInternalsTest::MessageHandler::GetNetLogLoggerLog
,
211 base::Unretained(this)));
214 void NetInternalsTest::MessageHandler::RunJavascriptCallback(
215 base::Value
* value
) {
216 web_ui()->CallJavascriptFunction("NetInternalsTest.callback", *value
);
219 void NetInternalsTest::MessageHandler::GetTestServerURL(
220 const base::ListValue
* list_value
) {
221 ASSERT_TRUE(net_internals_test_
->StartTestServer());
223 ASSERT_TRUE(list_value
->GetString(0, &path
));
224 GURL url
= net_internals_test_
->test_server()->GetURL(path
);
225 scoped_ptr
<base::Value
> url_value(base::Value::CreateStringValue(url
.spec()));
226 RunJavascriptCallback(url_value
.get());
229 void NetInternalsTest::MessageHandler::AddCacheEntry(
230 const base::ListValue
* list_value
) {
231 std::string hostname
;
232 std::string ip_literal
;
234 double expire_days_from_now
;
235 ASSERT_TRUE(list_value
->GetString(0, &hostname
));
236 ASSERT_TRUE(list_value
->GetString(1, &ip_literal
));
237 ASSERT_TRUE(list_value
->GetDouble(2, &net_error
));
238 ASSERT_TRUE(list_value
->GetDouble(3, &expire_days_from_now
));
239 ASSERT_TRUE(browser());
241 BrowserThread::PostTask(
242 BrowserThread::IO
, FROM_HERE
,
243 base::Bind(&AddCacheEntryOnIOThread
,
244 make_scoped_refptr(browser()->profile()->GetRequestContext()),
247 static_cast<int>(net_error
),
248 static_cast<int>(expire_days_from_now
)));
251 void NetInternalsTest::MessageHandler::LoadPage(
252 const base::ListValue
* list_value
) {
254 ASSERT_TRUE(list_value
->GetString(0, &url
));
255 LOG(WARNING
) << "url: [" << url
<< "]";
256 ui_test_utils::NavigateToURLWithDisposition(
260 ui_test_utils::BROWSER_TEST_NONE
);
263 void NetInternalsTest::MessageHandler::PrerenderPage(
264 const base::ListValue
* list_value
) {
265 std::string prerender_url
;
266 ASSERT_TRUE(list_value
->GetString(0, &prerender_url
));
268 net_internals_test_
->CreatePrerenderLoaderUrl(GURL(prerender_url
));
269 ui_test_utils::NavigateToURLWithDisposition(
273 ui_test_utils::BROWSER_TEST_NONE
);
276 void NetInternalsTest::MessageHandler::NavigateToPrerender(
277 const base::ListValue
* list_value
) {
278 content::RenderViewHost
* host
=
279 browser()->tab_strip_model()->GetWebContentsAt(1)->GetRenderViewHost();
280 host
->ExecuteJavascriptInWebFrame(base::string16(),
281 base::ASCIIToUTF16("Click()"));
284 void NetInternalsTest::MessageHandler::CreateIncognitoBrowser(
285 const base::ListValue
* list_value
) {
286 ASSERT_FALSE(incognito_browser_
);
287 incognito_browser_
= net_internals_test_
->CreateIncognitoBrowser();
289 // Tell the test harness that creation is complete.
290 base::StringValue
command_value("onIncognitoBrowserCreatedForTest");
291 web_ui()->CallJavascriptFunction("g_browser.receive", command_value
);
294 void NetInternalsTest::MessageHandler::CloseIncognitoBrowser(
295 const base::ListValue
* list_value
) {
296 ASSERT_TRUE(incognito_browser_
);
297 incognito_browser_
->tab_strip_model()->CloseAllTabs();
298 // Closing all a Browser's tabs will ultimately result in its destruction,
299 // thought it may not have been destroyed yet.
300 incognito_browser_
= NULL
;
303 void NetInternalsTest::MessageHandler::EnableHttpPipelining(
304 const base::ListValue
* list_value
) {
306 ASSERT_TRUE(list_value
->GetBoolean(0, &enable
));
307 BrowserThread::PostTask(
308 BrowserThread::IO
, FROM_HERE
,
309 base::Bind(&EnableHttpPipeliningOnIOThread
,
310 make_scoped_refptr(browser()->profile()->GetRequestContext()),
314 void NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback(
315 const base::ListValue
* list_value
) {
316 std::string hostname
;
318 std::string raw_capability
;
319 net::HttpPipelinedHostCapability capability
;
320 ASSERT_TRUE(list_value
->GetString(0, &hostname
));
321 ASSERT_TRUE(list_value
->GetDouble(1, &port
));
322 ASSERT_TRUE(list_value
->GetString(2, &raw_capability
));
323 if (raw_capability
== "capable") {
324 capability
= net::PIPELINE_CAPABLE
;
325 } else if (raw_capability
== "incapable") {
326 capability
= net::PIPELINE_INCAPABLE
;
328 FAIL() << "Unexpected capability string: " << raw_capability
;
330 BrowserThread::PostTask(
331 BrowserThread::IO
, FROM_HERE
,
332 base::Bind(&AddDummyHttpPipelineFeedbackOnIOThread
,
333 make_scoped_refptr(browser()->profile()->GetRequestContext()),
335 static_cast<int>(port
),
339 void NetInternalsTest::MessageHandler::GetNetLogLoggerLog(
340 const base::ListValue
* list_value
) {
341 base::ScopedTempDir temp_directory
;
342 ASSERT_TRUE(temp_directory
.CreateUniqueTempDir());
343 base::FilePath temp_file
;
344 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_directory
.path(),
346 FILE* temp_file_handle
= base::OpenFile(temp_file
, "w");
347 ASSERT_TRUE(temp_file_handle
);
349 scoped_ptr
<base::Value
> constants(NetInternalsUI::GetConstants());
350 scoped_ptr
<net::NetLogLogger
> net_log_logger(new net::NetLogLogger(
351 temp_file_handle
, *constants
));
352 net_log_logger
->StartObserving(g_browser_process
->net_log());
353 g_browser_process
->net_log()->AddGlobalEntry(
354 net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED
);
355 net::BoundNetLog bound_net_log
= net::BoundNetLog::Make(
356 g_browser_process
->net_log(),
357 net::NetLog::SOURCE_URL_REQUEST
);
358 bound_net_log
.BeginEvent(net::NetLog::TYPE_REQUEST_ALIVE
);
359 net_log_logger
->StopObserving();
360 net_log_logger
.reset();
362 std::string log_contents
;
363 ASSERT_TRUE(base::ReadFileToString(temp_file
, &log_contents
));
364 ASSERT_GT(log_contents
.length(), 0u);
366 scoped_ptr
<base::Value
> log_contents_value(
367 new base::StringValue(log_contents
));
368 RunJavascriptCallback(log_contents_value
.get());
371 ////////////////////////////////////////////////////////////////////////////////
373 ////////////////////////////////////////////////////////////////////////////////
375 NetInternalsTest::NetInternalsTest()
376 : test_server_started_(false) {
377 message_handler_
.reset(new MessageHandler(this));
380 NetInternalsTest::~NetInternalsTest() {
383 void NetInternalsTest::SetUp() {
384 #if defined(OS_WIN) && defined(USE_AURA)
385 // The NetInternalsTest.netInternalsTimelineViewScrollbar test requires real
386 // GL bindings to pass on Win7 Aura.
390 WebUIBrowserTest::SetUp();
393 void NetInternalsTest::SetUpCommandLine(CommandLine
* command_line
) {
394 WebUIBrowserTest::SetUpCommandLine(command_line
);
395 // Needed to test the prerender view.
396 command_line
->AppendSwitchASCII(switches::kPrerenderMode
,
397 switches::kPrerenderModeSwitchValueEnabled
);
400 void NetInternalsTest::SetUpOnMainThread() {
401 WebUIBrowserTest::SetUpOnMainThread();
402 // Increase the memory allowed in a prerendered page above normal settings,
403 // as debug builds use more memory and often go over the usual limit.
404 Profile
* profile
= browser()->profile();
405 prerender::PrerenderManager
* prerender_manager
=
406 prerender::PrerenderManagerFactory::GetForProfile(profile
);
407 prerender_manager
->mutable_config().max_bytes
= 1000 * 1024 * 1024;
410 content::WebUIMessageHandler
* NetInternalsTest::GetMockMessageHandler() {
411 return message_handler_
.get();
414 GURL
NetInternalsTest::CreatePrerenderLoaderUrl(
415 const GURL
& prerender_url
) {
416 EXPECT_TRUE(StartTestServer());
417 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
418 replacement_text
.push_back(
419 make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url
.spec()));
420 replacement_text
.push_back(
421 make_pair("REPLACE_WITH_DESTINATION_URL", prerender_url
.spec()));
422 std::string replacement_path
;
423 EXPECT_TRUE(net::SpawnedTestServer::GetFilePathWithReplacements(
424 "files/prerender/prerender_loader.html",
427 GURL url_loader
= test_server()->GetURL(replacement_path
);
431 bool NetInternalsTest::StartTestServer() {
432 if (test_server_started_
)
434 test_server_started_
= test_server()->Start();
435 return test_server_started_
;