// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <vector> #include "base/message_loop.h" #include "chrome/browser/history/history.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "content/browser/browser_thread.h" #include "googleurl/src/gurl.h" namespace { // Helper to debug intermittent test hangs/timeouts. // TODO(phajdan.jr): remove when http://crbug.com/57994 is fixed. void Checkpoint(const char* message, const base::TimeTicks& start_time) { LOG(INFO) << message << " : " << (base::TimeTicks::Now() - start_time).InMilliseconds() << " ms" << std::flush; } // Note: WaitableEvent is not used for synchronization between the main thread // and history backend thread because the history subsystem posts tasks back // to the main thread. Had we tried to Signal an event in such a task // and Wait for it on the main thread, the task would not run at all because // the main thread would be blocked on the Wait call, resulting in a deadlock. // A task to be scheduled on the history backend thread. // Notifies the main thread after all history backend thread tasks have run. class WaitForHistoryTask : public HistoryDBTask { public: WaitForHistoryTask() { } virtual bool RunOnDBThread(history::HistoryBackend* backend, history::HistoryDatabase* db) { return true; } virtual void DoneRunOnMainThread() { MessageLoop::current()->Quit(); } private: DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask); }; // Enumerates all history contents on the backend thread. class HistoryEnumerator : public HistoryService::URLEnumerator { public: explicit HistoryEnumerator(HistoryService* history) { EXPECT_TRUE(history); if (!history) return; BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(history, &HistoryService::IterateURLs, this)); ui_test_utils::RunMessageLoop(); } virtual void OnURL(const GURL& url) { urls_.push_back(url); } virtual void OnComplete(bool success) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask()); } std::vector<GURL>& urls() { return urls_; } private: std::vector<GURL> urls_; DISALLOW_COPY_AND_ASSIGN(HistoryEnumerator); }; class HistoryBrowserTest : public InProcessBrowserTest { protected: PrefService* GetPrefs() { return GetProfile()->GetPrefs(); } Profile* GetProfile() { return browser()->GetProfile(); } HistoryService* GetHistoryService() { return GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS); } std::vector<GURL> GetHistoryContents() { HistoryEnumerator enumerator(GetHistoryService()); return enumerator.urls(); } GURL GetTestUrl() { return ui_test_utils::GetTestUrl( FilePath(FilePath::kCurrentDirectory), FilePath(FILE_PATH_LITERAL("title2.html"))); } void WaitForHistoryBackendToRun() { CancelableRequestConsumerTSimple<int> request_consumer; scoped_refptr<HistoryDBTask> task(new WaitForHistoryTask()); HistoryService* history = GetHistoryService(); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(history, &HistoryService::ScheduleDBTask, task, &request_consumer)); ui_test_utils::RunMessageLoop(); } void ExpectEmptyHistory() { std::vector<GURL> urls(GetHistoryContents()); EXPECT_EQ(0U, urls.size()); } }; // Test that the browser history is saved (default setting). IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabled) { EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)); EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS)); EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::IMPLICIT_ACCESS)); ui_test_utils::WaitForHistoryToLoad(browser()); ExpectEmptyHistory(); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); WaitForHistoryBackendToRun(); { std::vector<GURL> urls(GetHistoryContents()); ASSERT_EQ(1U, urls.size()); EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); } } // Test that disabling saving browser history really works. // TODO(phajdan.jr): remove debug code when http://crbug.com/57994 is fixed. IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabled) { base::TimeTicks start_time = base::TimeTicks::Now(); GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS)); EXPECT_FALSE(GetProfile()->GetHistoryService(Profile::IMPLICIT_ACCESS)); Checkpoint("Before waiting for history to load", start_time); ui_test_utils::WaitForHistoryToLoad(browser()); Checkpoint("After waiting for history to load", start_time); ExpectEmptyHistory(); Checkpoint("After checking history", start_time); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); Checkpoint("After NavigateToURL", start_time); WaitForHistoryBackendToRun(); Checkpoint("After waiting for history backend to run", start_time); ExpectEmptyHistory(); Checkpoint("After second check", start_time); } // Test that changing the pref takes effect immediately // when the browser is running. // TODO(phajdan.jr): remove debug code when http://crbug.com/57994 is fixed. IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabledThenDisabled) { base::TimeTicks start_time = base::TimeTicks::Now(); EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)); Checkpoint("Before waiting for history to load", start_time); ui_test_utils::WaitForHistoryToLoad(browser()); Checkpoint("After waiting for history to load", start_time); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); Checkpoint("After first NavigateToURL", start_time); WaitForHistoryBackendToRun(); Checkpoint("After waiting for history backend to run", start_time); { std::vector<GURL> urls(GetHistoryContents()); Checkpoint("After first GetHistoryContents", start_time); ASSERT_EQ(1U, urls.size()); EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); } GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); Checkpoint("After second NavigateToURL", start_time); WaitForHistoryBackendToRun(); Checkpoint("After waiting for history backend to run (2nd time)", start_time); { // No additional entries should be present in the history. std::vector<GURL> urls(GetHistoryContents()); Checkpoint("After second GetHistoryContents", start_time); ASSERT_EQ(1U, urls.size()); EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); } } // Test that changing the pref takes effect immediately // when the browser is running. IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabledThenEnabled) { GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true); ui_test_utils::WaitForHistoryToLoad(browser()); ExpectEmptyHistory(); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); WaitForHistoryBackendToRun(); ExpectEmptyHistory(); GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, false); ui_test_utils::NavigateToURL(browser(), GetTestUrl()); WaitForHistoryBackendToRun(); { std::vector<GURL> urls(GetHistoryContents()); ASSERT_EQ(1U, urls.size()); EXPECT_EQ(GetTestUrl().spec(), urls[0].spec()); } } } // namespace