blob: 32d3bf567442f058c8e53c18bc799baa53386cc1 [file] [log] [blame]
// Copyright (c) 2012 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 "chrome/browser/search_engines/template_url_service_test_util.h"
#include "base/bind.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
namespace {
// A callback used to coordinate when the database has finished processing
// requests. See note in BlockTillServiceProcessesRequests for details.
//
// Schedules a QuitClosure on the message loop it was created with.
void QuitCallback(MessageLoop* message_loop) {
message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}
// Blocks the caller until thread has finished servicing all pending
// requests.
static void WaitForThreadToProcessRequests(BrowserThread::ID identifier) {
// Schedule a task on the thread that is processed after all
// pending requests on the thread.
BrowserThread::PostTask(identifier, FROM_HERE,
base::Bind(&QuitCallback, MessageLoop::current()));
MessageLoop::current()->Run();
}
} // namespace
// Subclass the TestingProfile so that it can return a WebDataService.
class TemplateURLServiceTestingProfile : public TestingProfile {
public:
TemplateURLServiceTestingProfile()
: TestingProfile(),
db_thread_(BrowserThread::DB),
io_thread_(BrowserThread::IO) {
}
void SetUp();
void TearDown();
// Starts the I/O thread. This isn't done automatically because not every test
// needs this.
void StartIOThread() {
io_thread_.StartIOThread();
}
static scoped_refptr<RefcountedProfileKeyedService>
GetWebDataServiceForTemplateURLServiceTestingProfile(Profile* profile);
private:
scoped_refptr<WebDataService> service_;
ScopedTempDir temp_dir_;
content::TestBrowserThread db_thread_;
content::TestBrowserThread io_thread_;
};
// Trivial subclass of TemplateURLService that records the last invocation of
// SetKeywordSearchTermsForURL.
class TestingTemplateURLService : public TemplateURLService {
public:
static ProfileKeyedService* Build(Profile* profile) {
return new TestingTemplateURLService(profile);
}
explicit TestingTemplateURLService(Profile* profile)
: TemplateURLService(profile) {
}
string16 GetAndClearSearchTerm() {
string16 search_term;
search_term.swap(search_term_);
return search_term;
}
protected:
virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
const GURL& url,
const string16& term) {
search_term_ = term;
}
private:
string16 search_term_;
DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLService);
};
void TemplateURLServiceTestingProfile::SetUp() {
db_thread_.Start();
// Make unique temp directory.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
FilePath path = temp_dir_.path().AppendASCII("TestDataService.db");
service_ = new WebDataService;
ASSERT_TRUE(service_->InitWithPath(path));
}
void TemplateURLServiceTestingProfile::TearDown() {
// Clear the request context so it will get deleted. This should be done
// before shutting down the I/O thread to avoid memory leaks.
ResetRequestContext();
// Wait for the delete of the request context to happen.
if (io_thread_.IsRunning())
TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests();
// The I/O thread must be shutdown before the DB thread.
io_thread_.Stop();
// Clean up the test directory.
if (service_.get()) {
service_->ShutdownOnUIThread();
service_ = NULL;
}
// Note that we must ensure the DB thread is stopped after WDS
// shutdown (so it can commit pending transactions) but before
// deleting the test profile directory, otherwise we may not be
// able to delete it due to an open transaction.
// Schedule another task on the DB thread to notify us that it's safe to
// carry on with the test.
base::WaitableEvent done(false, false);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
done.Wait();
db_thread_.Stop();
}
scoped_refptr<RefcountedProfileKeyedService>
TemplateURLServiceTestingProfile::
GetWebDataServiceForTemplateURLServiceTestingProfile(Profile* profile) {
TemplateURLServiceTestingProfile* test_profile =
reinterpret_cast<TemplateURLServiceTestingProfile*>(profile);
return test_profile->service_;
}
TemplateURLServiceTestUtil::TemplateURLServiceTestUtil()
: ui_thread_(BrowserThread::UI, &message_loop_),
changed_count_(0) {
}
TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() {
}
void TemplateURLServiceTestUtil::SetUp() {
profile_.reset(new TemplateURLServiceTestingProfile());
WebDataServiceFactory::GetInstance()->SetTestingFactory(
profile_.get(), TemplateURLServiceTestingProfile::
GetWebDataServiceForTemplateURLServiceTestingProfile);
profile_->SetUp();
TemplateURLService* service = static_cast<TemplateURLService*>(
TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile_.get(), TestingTemplateURLService::Build));
service->AddObserver(this);
}
void TemplateURLServiceTestUtil::TearDown() {
if (profile_.get()) {
profile_->TearDown();
profile_.reset();
}
UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
// Flush the message loop to make application verifiers happy.
message_loop_.RunAllPending();
}
void TemplateURLServiceTestUtil::OnTemplateURLServiceChanged() {
changed_count_++;
}
int TemplateURLServiceTestUtil::GetObserverCount() {
return changed_count_;
}
void TemplateURLServiceTestUtil::ResetObserverCount() {
changed_count_ = 0;
}
void TemplateURLServiceTestUtil::BlockTillServiceProcessesRequests() {
WaitForThreadToProcessRequests(BrowserThread::DB);
}
void TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests() {
WaitForThreadToProcessRequests(BrowserThread::IO);
}
void TemplateURLServiceTestUtil::VerifyLoad() {
ASSERT_FALSE(model()->loaded());
model()->Load();
BlockTillServiceProcessesRequests();
EXPECT_EQ(1, GetObserverCount());
ResetObserverCount();
}
void TemplateURLServiceTestUtil::ChangeModelToLoadState() {
model()->ChangeToLoadedState();
// Initialize the web data service so that the database gets updated with
// any changes made.
model()->service_ = WebDataServiceFactory::GetForProfile(
profile_.get(), Profile::EXPLICIT_ACCESS);
}
void TemplateURLServiceTestUtil::ClearModel() {
TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
profile_.get(), NULL);
}
void TemplateURLServiceTestUtil::ResetModel(bool verify_load) {
TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile_.get(), TestingTemplateURLService::Build);
model()->AddObserver(this);
changed_count_ = 0;
if (verify_load)
VerifyLoad();
}
string16 TemplateURLServiceTestUtil::GetAndClearSearchTerm() {
return
static_cast<TestingTemplateURLService*>(model())->GetAndClearSearchTerm();
}
void TemplateURLServiceTestUtil::SetGoogleBaseURL(const GURL& base_url) const {
DCHECK(base_url.is_valid());
UIThreadSearchTermsData data(profile_.get());
GoogleURLTracker::UpdatedDetails urls(GURL(data.GoogleBaseURLValue()),
base_url);
UIThreadSearchTermsData::SetGoogleBaseURL(base_url.spec());
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
content::Source<Profile>(profile_.get()),
content::Details<GoogleURLTracker::UpdatedDetails>(&urls));
}
void TemplateURLServiceTestUtil::SetManagedDefaultSearchPreferences(
bool enabled,
const std::string& name,
const std::string& keyword,
const std::string& search_url,
const std::string& suggest_url,
const std::string& icon_url,
const std::string& encodings) {
TestingPrefService* pref_service = profile_->GetTestingPrefService();
pref_service->SetManagedPref(prefs::kDefaultSearchProviderEnabled,
Value::CreateBooleanValue(enabled));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderName,
Value::CreateStringValue(name));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderKeyword,
Value::CreateStringValue(keyword));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderSearchURL,
Value::CreateStringValue(search_url));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderSuggestURL,
Value::CreateStringValue(suggest_url));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderIconURL,
Value::CreateStringValue(icon_url));
pref_service->SetManagedPref(prefs::kDefaultSearchProviderEncodings,
Value::CreateStringValue(encodings));
model()->Observe(chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
}
void TemplateURLServiceTestUtil::RemoveManagedDefaultSearchPreferences() {
TestingPrefService* pref_service = profile_->GetTestingPrefService();
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderEnabled);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderName);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderKeyword);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderSearchURL);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderSuggestURL);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderIconURL);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderEncodings);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderID);
pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderPrepopulateID);
model()->Observe(chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
}
TemplateURLService* TemplateURLServiceTestUtil::model() const {
return TemplateURLServiceFactory::GetForProfile(profile_.get());
}
TestingProfile* TemplateURLServiceTestUtil::profile() const {
return profile_.get();
}
void TemplateURLServiceTestUtil::StartIOThread() {
profile_->StartIOThread();
}
void TemplateURLServiceTestUtil::PumpLoop() {
message_loop_.RunAllPending();
}