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. 4 5#include <vector> 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/message_loop/message_loop.h" 10#include "base/prefs/pref_service.h" 11#include "base/strings/utf_string_conversions.h" 12#include "chrome/app/chrome_command_ids.h" 13#include "chrome/browser/history/history_db_task.h" 14#include "chrome/browser/history/history_service.h" 15#include "chrome/browser/history/history_service_factory.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/browser.h" 18#include "chrome/browser/ui/browser_commands.h" 19#include "chrome/browser/ui/tabs/tab_strip_model.h" 20#include "chrome/common/chrome_switches.h" 21#include "chrome/common/pref_names.h" 22#include "chrome/common/url_constants.h" 23#include "chrome/test/base/in_process_browser_test.h" 24#include "chrome/test/base/ui_test_utils.h" 25#include "content/public/browser/web_contents.h" 26#include "content/public/test/browser_test_utils.h" 27#include "content/public/test/test_browser_thread.h" 28#include "url/gurl.h" 29 30using content::BrowserThread; 31 32namespace { 33 34// Note: WaitableEvent is not used for synchronization between the main thread 35// and history backend thread because the history subsystem posts tasks back 36// to the main thread. Had we tried to Signal an event in such a task 37// and Wait for it on the main thread, the task would not run at all because 38// the main thread would be blocked on the Wait call, resulting in a deadlock. 39 40// A task to be scheduled on the history backend thread. 41// Notifies the main thread after all history backend thread tasks have run. 42class WaitForHistoryTask : public history::HistoryDBTask { 43 public: 44 WaitForHistoryTask() {} 45 46 virtual bool RunOnDBThread(history::HistoryBackend* backend, 47 history::HistoryDatabase* db) OVERRIDE { 48 return true; 49 } 50 51 virtual void DoneRunOnMainThread() OVERRIDE { 52 base::MessageLoop::current()->Quit(); 53 } 54 55 private: 56 virtual ~WaitForHistoryTask() {} 57 58 DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask); 59}; 60 61} // namespace 62 63class HistoryBrowserTest : public InProcessBrowserTest { 64 protected: 65 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 66 command_line->AppendSwitch(switches::kEnableFileCookies); 67 } 68 69 PrefService* GetPrefs() { 70 return GetProfile()->GetPrefs(); 71 } 72 73 Profile* GetProfile() { 74 return browser()->profile(); 75 } 76 77 std::vector<GURL> GetHistoryContents() { 78 ui_test_utils::HistoryEnumerator enumerator(GetProfile()); 79 return enumerator.urls(); 80 } 81 82 GURL GetTestUrl() { 83 return ui_test_utils::GetTestUrl( 84 base::FilePath(base::FilePath::kCurrentDirectory), 85 base::FilePath(FILE_PATH_LITERAL("title2.html"))); 86 } 87 88 void WaitForHistoryBackendToRun() { 89 base::CancelableTaskTracker task_tracker; 90 scoped_ptr<history::HistoryDBTask> task(new WaitForHistoryTask()); 91 HistoryService* history = 92 HistoryServiceFactory::GetForProfile(GetProfile(), 93 Profile::EXPLICIT_ACCESS); 94 history->HistoryService::ScheduleDBTask(task.Pass(), &task_tracker); 95 content::RunMessageLoop(); 96 } 97 98 void ExpectEmptyHistory() { 99 std::vector<GURL> urls(GetHistoryContents()); 100 EXPECT_EQ(0U, urls.size()); 101 } 102 103 void LoadAndWaitForURL(const GURL& url) { 104 base::string16 expected_title(base::ASCIIToUTF16("OK")); 105 content::TitleWatcher title_watcher( 106 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); 107 title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL")); 108 ui_test_utils::NavigateToURL(browser(), url); 109 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 110 } 111 112 void LoadAndWaitForFile(const char* filename) { 113 GURL url = ui_test_utils::GetTestUrl( 114 base::FilePath().AppendASCII("History"), 115 base::FilePath().AppendASCII(filename)); 116 LoadAndWaitForURL(url); 117 } 118}; 119 120// Test that the browser history is saved (default setting). 121IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabled) { 122 EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)); 123 124 EXPECT_TRUE(HistoryServiceFactory::GetForProfile( 125 GetProfile(), Profile::EXPLICIT_ACCESS)); 126 EXPECT_TRUE(HistoryServiceFactory::GetForProfile( 127 GetProfile(), Profile::IMPLICIT_ACCESS)); 128 129 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 130 browser()->profile(), Profile::EXPLICIT_ACCESS)); 131 ExpectEmptyHistory(); 132 133 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 134 WaitForHistoryBackendToRun(); 135 136 { 137 std::vector<GURL> urls(GetHistoryContents()); 138 ASSERT_EQ(1U, urls.size()); 139 EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); 140 } 141} 142 143// Test that disabling saving browser history really works. 144IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabled) { 145 GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); 146 147 EXPECT_TRUE(HistoryServiceFactory::GetForProfile( 148 GetProfile(), Profile::EXPLICIT_ACCESS)); 149 EXPECT_FALSE(HistoryServiceFactory::GetForProfile( 150 GetProfile(), Profile::IMPLICIT_ACCESS)); 151 152 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 153 browser()->profile(), Profile::EXPLICIT_ACCESS)); 154 ExpectEmptyHistory(); 155 156 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 157 WaitForHistoryBackendToRun(); 158 ExpectEmptyHistory(); 159} 160 161// Test that changing the pref takes effect immediately 162// when the browser is running. 163IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabledThenDisabled) { 164 EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)); 165 166 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 167 browser()->profile(), Profile::EXPLICIT_ACCESS)); 168 169 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 170 WaitForHistoryBackendToRun(); 171 172 { 173 std::vector<GURL> urls(GetHistoryContents()); 174 ASSERT_EQ(1U, urls.size()); 175 EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); 176 } 177 178 GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); 179 180 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 181 WaitForHistoryBackendToRun(); 182 183 { 184 // No additional entries should be present in the history. 185 std::vector<GURL> urls(GetHistoryContents()); 186 ASSERT_EQ(1U, urls.size()); 187 EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); 188 } 189} 190 191// Test that changing the pref takes effect immediately 192// when the browser is running. 193IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabledThenEnabled) { 194 GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); 195 196 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 197 browser()->profile(), Profile::EXPLICIT_ACCESS)); 198 ExpectEmptyHistory(); 199 200 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 201 WaitForHistoryBackendToRun(); 202 ExpectEmptyHistory(); 203 204 GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, false); 205 206 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 207 WaitForHistoryBackendToRun(); 208 209 { 210 std::vector<GURL> urls(GetHistoryContents()); 211 ASSERT_EQ(1U, urls.size()); 212 EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); 213 } 214} 215 216IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength1) { 217 // Test the history length for the following page transitions. 218 // -open-> Page 1. 219 LoadAndWaitForFile("history_length_test_page_1.html"); 220} 221 222IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength2) { 223 // Test the history length for the following page transitions. 224 // -open-> Page 2 -redirect-> Page 3. 225 LoadAndWaitForFile("history_length_test_page_2.html"); 226} 227 228IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength3) { 229 // Test the history length for the following page transitions. 230 // -open-> Page 1 -> open Page 2 -redirect Page 3. open Page 4 231 // -navigate_backward-> Page 3 -navigate_backward->Page 1 232 // -navigate_forward-> Page 3 -navigate_forward-> Page 4 233 LoadAndWaitForFile("history_length_test_page_1.html"); 234 LoadAndWaitForFile("history_length_test_page_2.html"); 235 LoadAndWaitForFile("history_length_test_page_4.html"); 236} 237 238IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, 239 ConsiderRedirectAfterGestureAsUserInitiated) { 240 // Test the history length for the following page transition. 241 // 242 // -open-> Page 11 -slow_redirect-> Page 12. 243 // 244 // If redirect occurs after a user gesture, e.g., mouse click, the 245 // redirect is more likely to be user-initiated rather than automatic. 246 // Therefore, Page 11 should be in the history in addition to Page 12. 247 LoadAndWaitForFile("history_length_test_page_11.html"); 248 249 content::SimulateMouseClick( 250 browser()->tab_strip_model()->GetActiveWebContents(), 0, 251 blink::WebMouseEvent::ButtonLeft); 252 LoadAndWaitForFile("history_length_test_page_11.html"); 253} 254 255IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, 256 ConsiderSlowRedirectAsUserInitiated) { 257 // Test the history length for the following page transition. 258 // 259 // -open-> Page 21 -redirect-> Page 22. 260 // 261 // If redirect occurs more than 5 seconds later after the page is loaded, 262 // the redirect is likely to be user-initiated. 263 // Therefore, Page 21 should be in the history in addition to Page 22. 264 LoadAndWaitForFile("history_length_test_page_21.html"); 265} 266 267// http://crbug.com/22111 268#if defined(OS_LINUX) 269#define MAYBE_HistorySearchXSS DISABLED_HistorySearchXSS 270#else 271#define MAYBE_HistorySearchXSS HistorySearchXSS 272#endif 273IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, MAYBE_HistorySearchXSS) { 274 GURL url(std::string(chrome::kChromeUIHistoryURL) + 275 "#q=%3Cimg%20src%3Dx%3Ax%20onerror%3D%22document.title%3D'XSS'%22%3E"); 276 ui_test_utils::NavigateToURL(browser(), url); 277 // Mainly, this is to ensure we send a synchronous message to the renderer 278 // so that we're not susceptible (less susceptible?) to a race condition. 279 // Should a race condition ever trigger, it won't result in flakiness. 280 int num = ui_test_utils::FindInPage( 281 browser()->tab_strip_model()->GetActiveWebContents(), 282 base::ASCIIToUTF16("<img"), true, 283 true, NULL, NULL); 284 EXPECT_GT(num, 0); 285 EXPECT_EQ(base::ASCIIToUTF16("History"), 286 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 287} 288 289// Verify that history persists after session restart. 290IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, PRE_HistoryPersists) { 291 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 292 std::vector<GURL> urls(GetHistoryContents()); 293 ASSERT_EQ(1u, urls.size()); 294 ASSERT_EQ(GetTestUrl(), urls[0]); 295} 296 297IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, HistoryPersists) { 298 std::vector<GURL> urls(GetHistoryContents()); 299 ASSERT_EQ(1u, urls.size()); 300 ASSERT_EQ(GetTestUrl(), urls[0]); 301} 302 303// Invalid URLs should not go in history. 304IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, InvalidURLNoHistory) { 305 GURL non_existant = ui_test_utils::GetTestUrl( 306 base::FilePath().AppendASCII("History"), 307 base::FilePath().AppendASCII("non_existant_file.html")); 308 ui_test_utils::NavigateToURL(browser(), non_existant); 309 ExpectEmptyHistory(); 310} 311 312// New tab page should not show up in history. 313IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NewTabNoHistory) { 314 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL)); 315 ExpectEmptyHistory(); 316} 317 318// Incognito browsing should not show up in history. 319IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, IncognitoNoHistory) { 320 ui_test_utils::NavigateToURL(CreateIncognitoBrowser(), GetTestUrl()); 321 ExpectEmptyHistory(); 322} 323 324// Multiple navigations to the same url should have a single history. 325IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NavigateMultiTimes) { 326 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 327 ui_test_utils::NavigateToURL(browser(), GetTestUrl()); 328 std::vector<GURL> urls(GetHistoryContents()); 329 ASSERT_EQ(1u, urls.size()); 330 ASSERT_EQ(GetTestUrl(), urls[0]); 331} 332 333// Verify history with multiple windows and tabs. 334IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, MultiTabsWindowsHistory) { 335 GURL url1 = GetTestUrl(); 336 GURL url2 = ui_test_utils::GetTestUrl( 337 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title1.html"))); 338 GURL url3 = ui_test_utils::GetTestUrl( 339 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html"))); 340 GURL url4 = ui_test_utils::GetTestUrl( 341 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("simple.html"))); 342 343 ui_test_utils::NavigateToURL(browser(), url1); 344 Browser* browser2 = CreateBrowser(browser()->profile()); 345 ui_test_utils::NavigateToURL(browser2, url2); 346 ui_test_utils::NavigateToURLWithDisposition( 347 browser2, url3, NEW_FOREGROUND_TAB, 348 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 349 ui_test_utils::NavigateToURLWithDisposition( 350 browser2, url4, NEW_FOREGROUND_TAB, 351 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 352 353 std::vector<GURL> urls(GetHistoryContents()); 354 ASSERT_EQ(4u, urls.size()); 355 ASSERT_EQ(url4, urls[0]); 356 ASSERT_EQ(url3, urls[1]); 357 ASSERT_EQ(url2, urls[2]); 358 ASSERT_EQ(url1, urls[3]); 359} 360 361// Downloaded URLs should not show up in history. 362IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, DownloadNoHistory) { 363 GURL download_url = ui_test_utils::GetTestUrl( 364 base::FilePath().AppendASCII("downloads"), 365 base::FilePath().AppendASCII("a_zip_file.zip")); 366 ui_test_utils::DownloadURL(browser(), download_url); 367 ExpectEmptyHistory(); 368} 369 370// HTTP meta-refresh redirects should have separate history entries. 371IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, RedirectHistory) { 372 GURL redirector = ui_test_utils::GetTestUrl( 373 base::FilePath().AppendASCII("History"), 374 base::FilePath().AppendASCII("redirector.html")); 375 GURL landing_url = ui_test_utils::GetTestUrl( 376 base::FilePath().AppendASCII("History"), 377 base::FilePath().AppendASCII("landing.html")); 378 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 379 browser(), redirector, 2); 380 ASSERT_EQ(landing_url, 381 browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); 382 std::vector<GURL> urls(GetHistoryContents()); 383 ASSERT_EQ(2u, urls.size()); 384 ASSERT_EQ(landing_url, urls[0]); 385 ASSERT_EQ(redirector, urls[1]); 386} 387 388// Verify that navigation brings current page to top of history list. 389IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NavigateBringPageToTop) { 390 GURL url1 = GetTestUrl(); 391 GURL url2 = ui_test_utils::GetTestUrl( 392 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html"))); 393 394 ui_test_utils::NavigateToURL(browser(), url1); 395 ui_test_utils::NavigateToURL(browser(), url2); 396 397 std::vector<GURL> urls(GetHistoryContents()); 398 ASSERT_EQ(2u, urls.size()); 399 ASSERT_EQ(url2, urls[0]); 400 ASSERT_EQ(url1, urls[1]); 401} 402 403// Verify that reloading a page brings it to top of history list. 404IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, ReloadBringPageToTop) { 405 GURL url1 = GetTestUrl(); 406 GURL url2 = ui_test_utils::GetTestUrl( 407 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html"))); 408 409 ui_test_utils::NavigateToURL(browser(), url1); 410 ui_test_utils::NavigateToURLWithDisposition( 411 browser(), url2, NEW_BACKGROUND_TAB, 412 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 413 414 std::vector<GURL> urls(GetHistoryContents()); 415 ASSERT_EQ(2u, urls.size()); 416 ASSERT_EQ(url2, urls[0]); 417 ASSERT_EQ(url1, urls[1]); 418 419 content::WebContents* tab = 420 browser()->tab_strip_model()->GetActiveWebContents(); 421 tab->GetController().Reload(false); 422 content::WaitForLoadStop(tab); 423 424 urls = GetHistoryContents(); 425 ASSERT_EQ(2u, urls.size()); 426 ASSERT_EQ(url1, urls[0]); 427 ASSERT_EQ(url2, urls[1]); 428} 429 430// Verify that back/forward brings current page to top of history list. 431IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, BackForwardBringPageToTop) { 432 GURL url1 = GetTestUrl(); 433 GURL url2 = ui_test_utils::GetTestUrl( 434 base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html"))); 435 436 ui_test_utils::NavigateToURL(browser(), url1); 437 ui_test_utils::NavigateToURL(browser(), url2); 438 439 content::WebContents* tab = 440 browser()->tab_strip_model()->GetActiveWebContents(); 441 chrome::GoBack(browser(), CURRENT_TAB); 442 content::WaitForLoadStop(tab); 443 444 std::vector<GURL> urls(GetHistoryContents()); 445 ASSERT_EQ(2u, urls.size()); 446 ASSERT_EQ(url1, urls[0]); 447 ASSERT_EQ(url2, urls[1]); 448 449 chrome::GoForward(browser(), CURRENT_TAB); 450 content::WaitForLoadStop(tab); 451 urls = GetHistoryContents(); 452 ASSERT_EQ(2u, urls.size()); 453 ASSERT_EQ(url2, urls[0]); 454 ASSERT_EQ(url1, urls[1]); 455} 456 457// Verify that submitting form adds target page to history list. 458IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SubmitFormAddsTargetPage) { 459 GURL form = ui_test_utils::GetTestUrl( 460 base::FilePath().AppendASCII("History"), 461 base::FilePath().AppendASCII("form.html")); 462 GURL target = ui_test_utils::GetTestUrl( 463 base::FilePath().AppendASCII("History"), 464 base::FilePath().AppendASCII("target.html")); 465 ui_test_utils::NavigateToURL(browser(), form); 466 467 content::WebContents* web_contents = 468 browser()->tab_strip_model()->GetActiveWebContents(); 469 base::string16 expected_title(base::ASCIIToUTF16("Target Page")); 470 content::TitleWatcher title_watcher( 471 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); 472 ASSERT_TRUE(content::ExecuteScript( 473 web_contents, "document.getElementById('form').submit()")); 474 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 475 476 std::vector<GURL> urls(GetHistoryContents()); 477 ASSERT_EQ(2u, urls.size()); 478 ASSERT_EQ(target, urls[0]); 479 ASSERT_EQ(form, urls[1]); 480} 481 482// Verify history shortcut opens only one history tab per window. Also, make 483// sure that existing history tab is activated. 484IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, OneHistoryTabPerWindow) { 485 GURL history_url(chrome::kChromeUIHistoryURL); 486 487 // Even after navigate completes, the currently-active tab title is 488 // 'Loading...' for a brief time while the history page loads. 489 content::WebContents* web_contents = 490 browser()->tab_strip_model()->GetActiveWebContents(); 491 base::string16 expected_title(base::ASCIIToUTF16("History")); 492 content::TitleWatcher title_watcher(web_contents, expected_title); 493 chrome::ExecuteCommand(browser(), IDC_SHOW_HISTORY); 494 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 495 496 ui_test_utils::NavigateToURLWithDisposition( 497 browser(), 498 GURL(url::kAboutBlankURL), 499 NEW_FOREGROUND_TAB, 500 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 501 chrome::ExecuteCommand(browser(), IDC_SHOW_HISTORY); 502 503 content::WebContents* active_web_contents = 504 browser()->tab_strip_model()->GetActiveWebContents(); 505 ASSERT_EQ(web_contents, active_web_contents); 506 ASSERT_EQ(history_url, active_web_contents->GetURL()); 507 508 content::WebContents* second_tab = 509 browser()->tab_strip_model()->GetWebContentsAt(1); 510 ASSERT_NE(history_url, second_tab->GetURL()); 511} 512