template_url_service_test_util.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 "chrome/browser/search_engines/template_url_service_test_util.h"
6
7#include "base/bind.h"
8#include "base/message_loop.h"
9#include "base/path_service.h"
10#include "base/synchronization/waitable_event.h"
11#include "base/threading/thread.h"
12#include "chrome/browser/google/google_url_tracker.h"
13#include "chrome/browser/search_engines/search_terms_data.h"
14#include "chrome/browser/search_engines/template_url_service.h"
15#include "chrome/browser/search_engines/template_url_service_factory.h"
16#include "chrome/browser/webdata/web_data_service_factory.h"
17#include "chrome/common/chrome_notification_types.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/automation/value_conversion_util.h"
20#include "chrome/test/base/testing_pref_service_syncable.h"
21#include "chrome/test/base/testing_profile.h"
22#include "content/public/browser/notification_service.h"
23#include "content/public/test/test_browser_thread.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26
27#if defined(OS_CHROMEOS)
28#include "chrome/browser/google/google_util_chromeos.h"
29#endif
30
31using content::BrowserThread;
32
33namespace {
34
35// A callback used to coordinate when the database has finished processing
36// requests. See note in BlockTillServiceProcessesRequests for details.
37//
38// Schedules a QuitClosure on the message loop it was created with.
39void QuitCallback(MessageLoop* message_loop) {
40  message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
41}
42
43// Blocks the caller until thread has finished servicing all pending
44// requests.
45static void WaitForThreadToProcessRequests(BrowserThread::ID identifier) {
46  // Schedule a task on the thread that is processed after all
47  // pending requests on the thread.
48  BrowserThread::PostTask(identifier, FROM_HERE,
49                          base::Bind(&QuitCallback, MessageLoop::current()));
50  MessageLoop::current()->Run();
51}
52
53}  // namespace
54
55// Trivial subclass of TemplateURLService that records the last invocation of
56// SetKeywordSearchTermsForURL.
57class TestingTemplateURLService : public TemplateURLService {
58 public:
59  static ProfileKeyedService* Build(content::BrowserContext* profile) {
60    return new TestingTemplateURLService(static_cast<Profile*>(profile));
61  }
62
63  explicit TestingTemplateURLService(Profile* profile)
64      : TemplateURLService(profile) {
65  }
66
67  string16 GetAndClearSearchTerm() {
68    string16 search_term;
69    search_term.swap(search_term_);
70    return search_term;
71  }
72
73 protected:
74  virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
75                                           const GURL& url,
76                                           const string16& term) OVERRIDE {
77    search_term_ = term;
78  }
79
80 private:
81  string16 search_term_;
82
83  DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLService);
84};
85
86TemplateURLServiceTestUtil::TemplateURLServiceTestUtil()
87    : ui_thread_(BrowserThread::UI, &message_loop_),
88      db_thread_(BrowserThread::DB),
89      io_thread_(BrowserThread::IO),
90      changed_count_(0) {
91}
92
93TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() {
94}
95
96void TemplateURLServiceTestUtil::SetUp() {
97  // Make unique temp directory.
98  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
99  profile_.reset(new TestingProfile(temp_dir_.path()));
100  db_thread_.Start();
101  profile_->CreateWebDataService();
102
103  TemplateURLService* service = static_cast<TemplateURLService*>(
104      TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
105          profile_.get(), TestingTemplateURLService::Build));
106  service->AddObserver(this);
107
108#if defined(OS_CHROMEOS)
109  google_util::chromeos::ClearBrandForCurrentSession();
110#endif
111}
112
113void TemplateURLServiceTestUtil::TearDown() {
114  if (profile_.get()) {
115    // Clear the request context so it will get deleted. This should be done
116    // before shutting down the I/O thread to avoid memory leaks.
117    profile_->ResetRequestContext();
118    profile_.reset();
119  }
120
121  // Wait for the delete of the request context to happen.
122  if (io_thread_.IsRunning())
123    TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests();
124
125  // The I/O thread must be shutdown before the DB thread.
126  io_thread_.Stop();
127
128  // Note that we must ensure the DB thread is stopped after WDS
129  // shutdown (so it can commit pending transactions) but before
130  // deleting the test profile directory, otherwise we may not be
131  // able to delete it due to an open transaction.
132  // Schedule another task on the DB thread to notify us that it's safe to
133  // carry on with the test.
134  base::WaitableEvent done(false, false);
135  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
136      base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
137  done.Wait();
138  MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
139  MessageLoop::current()->Run();
140  db_thread_.Stop();
141
142  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
143
144  // Flush the message loop to make application verifiers happy.
145  message_loop_.RunUntilIdle();
146}
147
148void TemplateURLServiceTestUtil::OnTemplateURLServiceChanged() {
149  changed_count_++;
150}
151
152int TemplateURLServiceTestUtil::GetObserverCount() {
153  return changed_count_;
154}
155
156void TemplateURLServiceTestUtil::ResetObserverCount() {
157  changed_count_ = 0;
158}
159
160void TemplateURLServiceTestUtil::BlockTillServiceProcessesRequests() {
161  WaitForThreadToProcessRequests(BrowserThread::DB);
162}
163
164void TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests() {
165  WaitForThreadToProcessRequests(BrowserThread::IO);
166}
167
168void TemplateURLServiceTestUtil::VerifyLoad() {
169  ASSERT_FALSE(model()->loaded());
170  model()->Load();
171  BlockTillServiceProcessesRequests();
172  EXPECT_EQ(1, GetObserverCount());
173  ResetObserverCount();
174}
175
176void TemplateURLServiceTestUtil::ChangeModelToLoadState() {
177  model()->ChangeToLoadedState();
178  // Initialize the web data service so that the database gets updated with
179  // any changes made.
180
181  model()->service_ = WebDataService::FromBrowserContext(profile_.get());
182  BlockTillServiceProcessesRequests();
183}
184
185void TemplateURLServiceTestUtil::ClearModel() {
186  TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
187      profile_.get(), NULL);
188}
189
190void TemplateURLServiceTestUtil::ResetModel(bool verify_load) {
191  TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
192      profile_.get(), TestingTemplateURLService::Build);
193  model()->AddObserver(this);
194  changed_count_ = 0;
195  if (verify_load)
196    VerifyLoad();
197}
198
199string16 TemplateURLServiceTestUtil::GetAndClearSearchTerm() {
200  return
201      static_cast<TestingTemplateURLService*>(model())->GetAndClearSearchTerm();
202}
203
204void TemplateURLServiceTestUtil::SetGoogleBaseURL(const GURL& base_url) const {
205  DCHECK(base_url.is_valid());
206  UIThreadSearchTermsData data(profile_.get());
207  GoogleURLTracker::UpdatedDetails urls(GURL(data.GoogleBaseURLValue()),
208                                        base_url);
209  UIThreadSearchTermsData::SetGoogleBaseURL(base_url.spec());
210  content::NotificationService::current()->Notify(
211      chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
212      content::Source<Profile>(profile_.get()),
213      content::Details<GoogleURLTracker::UpdatedDetails>(&urls));
214}
215
216void TemplateURLServiceTestUtil::SetManagedDefaultSearchPreferences(
217    bool enabled,
218    const std::string& name,
219    const std::string& keyword,
220    const std::string& search_url,
221    const std::string& suggest_url,
222    const std::string& icon_url,
223    const std::string& encodings,
224    const std::string& alternate_url,
225    const std::string& search_terms_replacement_key) {
226  TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
227  pref_service->SetManagedPref(prefs::kDefaultSearchProviderEnabled,
228                               Value::CreateBooleanValue(enabled));
229  pref_service->SetManagedPref(prefs::kDefaultSearchProviderName,
230                               Value::CreateStringValue(name));
231  pref_service->SetManagedPref(prefs::kDefaultSearchProviderKeyword,
232                               Value::CreateStringValue(keyword));
233  pref_service->SetManagedPref(prefs::kDefaultSearchProviderSearchURL,
234                               Value::CreateStringValue(search_url));
235  pref_service->SetManagedPref(prefs::kDefaultSearchProviderSuggestURL,
236                               Value::CreateStringValue(suggest_url));
237  pref_service->SetManagedPref(prefs::kDefaultSearchProviderIconURL,
238                               Value::CreateStringValue(icon_url));
239  pref_service->SetManagedPref(prefs::kDefaultSearchProviderEncodings,
240                               Value::CreateStringValue(encodings));
241  pref_service->SetManagedPref(prefs::kDefaultSearchProviderAlternateURLs,
242      alternate_url.empty() ? new base::ListValue() :
243          CreateListValueFrom(alternate_url));
244  pref_service->SetManagedPref(
245      prefs::kDefaultSearchProviderSearchTermsReplacementKey,
246      Value::CreateStringValue(search_terms_replacement_key));
247  model()->Observe(chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
248                   content::NotificationService::AllSources(),
249                   content::NotificationService::NoDetails());
250}
251
252void TemplateURLServiceTestUtil::RemoveManagedDefaultSearchPreferences() {
253  TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
254  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderEnabled);
255  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderName);
256  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderKeyword);
257  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderSearchURL);
258  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderSuggestURL);
259  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderIconURL);
260  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderEncodings);
261  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderAlternateURLs);
262  pref_service->RemoveManagedPref(
263      prefs::kDefaultSearchProviderSearchTermsReplacementKey);
264  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderID);
265  pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderPrepopulateID);
266  model()->Observe(chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
267                   content::NotificationService::AllSources(),
268                   content::NotificationService::NoDetails());
269}
270
271TemplateURLService* TemplateURLServiceTestUtil::model() const {
272  return TemplateURLServiceFactory::GetForProfile(profile_.get());
273}
274
275TestingProfile* TemplateURLServiceTestUtil::profile() const {
276  return profile_.get();
277}
278
279void TemplateURLServiceTestUtil::StartIOThread() {
280  io_thread_.StartIOThread();
281}
282
283void TemplateURLServiceTestUtil::PumpLoop() {
284  message_loop_.RunUntilIdle();
285}
286