1// Copyright (c) 2010 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/message_loop.h"
8#include "chrome/browser/history/history.h"
9#include "chrome/browser/prefs/pref_service.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/common/pref_names.h"
13#include "chrome/test/in_process_browser_test.h"
14#include "chrome/test/ui_test_utils.h"
15#include "content/browser/browser_thread.h"
16#include "googleurl/src/gurl.h"
17
18namespace {
19
20// Helper to debug intermittent test hangs/timeouts.
21// TODO(phajdan.jr): remove when http://crbug.com/57994 is fixed.
22void Checkpoint(const char* message, const base::TimeTicks& start_time) {
23  LOG(INFO) << message << " : "
24            << (base::TimeTicks::Now() - start_time).InMilliseconds()
25            << " ms" << std::flush;
26}
27
28// Note: WaitableEvent is not used for synchronization between the main thread
29// and history backend thread because the history subsystem posts tasks back
30// to the main thread. Had we tried to Signal an event in such a task
31// and Wait for it on the main thread, the task would not run at all because
32// the main thread would be blocked on the Wait call, resulting in a deadlock.
33
34// A task to be scheduled on the history backend thread.
35// Notifies the main thread after all history backend thread tasks have run.
36class WaitForHistoryTask : public HistoryDBTask {
37 public:
38  WaitForHistoryTask() {
39  }
40
41  virtual bool RunOnDBThread(history::HistoryBackend* backend,
42                             history::HistoryDatabase* db) {
43    return true;
44  }
45
46  virtual void DoneRunOnMainThread() {
47    MessageLoop::current()->Quit();
48  }
49
50 private:
51  DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
52};
53
54// Enumerates all history contents on the backend thread.
55class HistoryEnumerator : public HistoryService::URLEnumerator {
56 public:
57  explicit HistoryEnumerator(HistoryService* history) {
58    EXPECT_TRUE(history);
59    if (!history)
60      return;
61
62    BrowserThread::PostTask(
63        BrowserThread::UI,
64        FROM_HERE,
65        NewRunnableMethod(history, &HistoryService::IterateURLs, this));
66    ui_test_utils::RunMessageLoop();
67  }
68
69  virtual void OnURL(const GURL& url) {
70    urls_.push_back(url);
71  }
72
73  virtual void OnComplete(bool success) {
74    BrowserThread::PostTask(
75        BrowserThread::UI,
76        FROM_HERE,
77        new MessageLoop::QuitTask());
78  }
79
80  std::vector<GURL>& urls() { return urls_; }
81
82 private:
83  std::vector<GURL> urls_;
84
85  DISALLOW_COPY_AND_ASSIGN(HistoryEnumerator);
86};
87
88class HistoryBrowserTest : public InProcessBrowserTest {
89 protected:
90  PrefService* GetPrefs() {
91    return GetProfile()->GetPrefs();
92  }
93
94  Profile* GetProfile() {
95    return browser()->GetProfile();
96  }
97
98  HistoryService* GetHistoryService() {
99    return GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
100  }
101
102  std::vector<GURL> GetHistoryContents() {
103    HistoryEnumerator enumerator(GetHistoryService());
104    return enumerator.urls();
105  }
106
107  GURL GetTestUrl() {
108    return ui_test_utils::GetTestUrl(
109        FilePath(FilePath::kCurrentDirectory),
110        FilePath(FILE_PATH_LITERAL("title2.html")));
111  }
112
113  void WaitForHistoryBackendToRun() {
114    CancelableRequestConsumerTSimple<int> request_consumer;
115    scoped_refptr<HistoryDBTask> task(new WaitForHistoryTask());
116    HistoryService* history = GetHistoryService();
117    BrowserThread::PostTask(BrowserThread::UI,
118                            FROM_HERE,
119                            NewRunnableMethod(history,
120                                              &HistoryService::ScheduleDBTask,
121                                              task,
122                                              &request_consumer));
123    ui_test_utils::RunMessageLoop();
124  }
125
126  void ExpectEmptyHistory() {
127    std::vector<GURL> urls(GetHistoryContents());
128    EXPECT_EQ(0U, urls.size());
129  }
130};
131
132// Test that the browser history is saved (default setting).
133IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabled) {
134  EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled));
135
136  EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS));
137  EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::IMPLICIT_ACCESS));
138
139  ui_test_utils::WaitForHistoryToLoad(browser());
140  ExpectEmptyHistory();
141
142  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
143  WaitForHistoryBackendToRun();
144
145  {
146    std::vector<GURL> urls(GetHistoryContents());
147    ASSERT_EQ(1U, urls.size());
148    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
149  }
150}
151
152// Test that disabling saving browser history really works.
153// TODO(phajdan.jr): remove debug code when http://crbug.com/57994 is fixed.
154IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabled) {
155  base::TimeTicks start_time = base::TimeTicks::Now();
156
157  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
158
159  EXPECT_TRUE(GetProfile()->GetHistoryService(Profile::EXPLICIT_ACCESS));
160  EXPECT_FALSE(GetProfile()->GetHistoryService(Profile::IMPLICIT_ACCESS));
161
162  Checkpoint("Before waiting for history to load", start_time);
163  ui_test_utils::WaitForHistoryToLoad(browser());
164  Checkpoint("After waiting for history to load", start_time);
165  ExpectEmptyHistory();
166  Checkpoint("After checking history", start_time);
167
168  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
169  Checkpoint("After NavigateToURL", start_time);
170  WaitForHistoryBackendToRun();
171  Checkpoint("After waiting for history backend to run", start_time);
172  ExpectEmptyHistory();
173  Checkpoint("After second check", start_time);
174}
175
176// Test that changing the pref takes effect immediately
177// when the browser is running.
178// TODO(phajdan.jr): remove debug code when http://crbug.com/57994 is fixed.
179IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabledThenDisabled) {
180  base::TimeTicks start_time = base::TimeTicks::Now();
181
182  EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled));
183
184  Checkpoint("Before waiting for history to load", start_time);
185  ui_test_utils::WaitForHistoryToLoad(browser());
186  Checkpoint("After waiting for history to load", start_time);
187
188  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
189  Checkpoint("After first NavigateToURL", start_time);
190  WaitForHistoryBackendToRun();
191  Checkpoint("After waiting for history backend to run", start_time);
192
193  {
194    std::vector<GURL> urls(GetHistoryContents());
195    Checkpoint("After first GetHistoryContents", start_time);
196    ASSERT_EQ(1U, urls.size());
197    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
198  }
199
200  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
201
202  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
203  Checkpoint("After second NavigateToURL", start_time);
204  WaitForHistoryBackendToRun();
205  Checkpoint("After waiting for history backend to run (2nd time)", start_time);
206
207  {
208    // No additional entries should be present in the history.
209    std::vector<GURL> urls(GetHistoryContents());
210    Checkpoint("After second GetHistoryContents", start_time);
211    ASSERT_EQ(1U, urls.size());
212    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
213  }
214}
215
216// Test that changing the pref takes effect immediately
217// when the browser is running.
218IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabledThenEnabled) {
219  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
220
221  ui_test_utils::WaitForHistoryToLoad(browser());
222  ExpectEmptyHistory();
223
224  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
225  WaitForHistoryBackendToRun();
226  ExpectEmptyHistory();
227
228  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, false);
229
230  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
231  WaitForHistoryBackendToRun();
232
233  {
234    std::vector<GURL> urls(GetHistoryContents());
235    ASSERT_EQ(1U, urls.size());
236    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
237  }
238}
239
240}  // namespace
241