// Copyright (c) 2011 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/google/google_url_tracker.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/testing_pref_service.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
// TestNotificationObserver ---------------------------------------------------
namespace {
class TestNotificationObserver : public NotificationObserver {
public:
TestNotificationObserver();
virtual ~TestNotificationObserver();
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
bool notified() const { return notified_; }
void clear_notified() { notified_ = false; }
private:
bool notified_;
};
TestNotificationObserver::TestNotificationObserver() : notified_(false) {
}
TestNotificationObserver::~TestNotificationObserver() {
}
void TestNotificationObserver::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
notified_ = true;
}
// TestInfoBarDelegate --------------------------------------------------------
class TestInfoBarDelegate : public InfoBarDelegate {
public:
TestInfoBarDelegate(GoogleURLTracker* google_url_tracker,
const GURL& new_google_url);
GoogleURLTracker* google_url_tracker() const { return google_url_tracker_; }
GURL new_google_url() const { return new_google_url_; }
private:
virtual ~TestInfoBarDelegate();
// InfoBarDelegate:
virtual InfoBar* CreateInfoBar();
GoogleURLTracker* google_url_tracker_;
GURL new_google_url_;
};
TestInfoBarDelegate::TestInfoBarDelegate(GoogleURLTracker* google_url_tracker,
const GURL& new_google_url)
: InfoBarDelegate(NULL),
google_url_tracker_(google_url_tracker),
new_google_url_(new_google_url) {
}
TestInfoBarDelegate::~TestInfoBarDelegate() {
}
InfoBar* TestInfoBarDelegate::CreateInfoBar() {
return NULL;
}
InfoBarDelegate* CreateTestInfobar(
TabContents* tab_contents,
GoogleURLTracker* google_url_tracker,
const GURL& new_google_url) {
return new TestInfoBarDelegate(google_url_tracker, new_google_url);
}
} // namespace
// GoogleURLTrackerTest -------------------------------------------------------
class GoogleURLTrackerTest : public testing::Test {
protected:
GoogleURLTrackerTest();
virtual ~GoogleURLTrackerTest();
// testing::Test
virtual void SetUp();
virtual void TearDown();
TestURLFetcher* GetFetcherByID(int expected_id);
void MockSearchDomainCheckResponse(int expected_id,
const std::string& domain);
void RequestServerCheck();
void FinishSleep();
void NotifyIPAddressChanged();
GURL GetFetchedGoogleURL();
void SetGoogleURL(const GURL& url);
void SetLastPromptedGoogleURL(const GURL& url);
GURL GetLastPromptedGoogleURL();
void SearchCommitted(const GURL& search_url);
void NavEntryCommitted();
bool InfoBarIsShown();
GURL GetInfoBarShowingURL();
void AcceptGoogleURL();
void CancelGoogleURL();
void InfoBarClosed();
void ExpectDefaultURLs();
scoped_ptr<TestNotificationObserver> observer_;
private:
MessageLoop* message_loop_;
BrowserThread* io_thread_;
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
TestingPrefService local_state_;
TestURLFetcherFactory fetcher_factory_;
NotificationRegistrar registrar_;
};
GoogleURLTrackerTest::GoogleURLTrackerTest()
: observer_(new TestNotificationObserver),
message_loop_(NULL),
io_thread_(NULL) {
}
GoogleURLTrackerTest::~GoogleURLTrackerTest() {
}
void GoogleURLTrackerTest::SetUp() {
message_loop_ = new MessageLoop(MessageLoop::TYPE_IO);
io_thread_ = new BrowserThread(BrowserThread::IO, message_loop_);
network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
browser::RegisterLocalState(&local_state_);
TestingBrowserProcess* testing_browser_process =
static_cast<TestingBrowserProcess*>(g_browser_process);
testing_browser_process->SetPrefService(&local_state_);
GoogleURLTracker* tracker = new GoogleURLTracker;
tracker->queue_wakeup_task_ = false;
MessageLoop::current()->RunAllPending();
testing_browser_process->SetGoogleURLTracker(tracker);
URLFetcher::set_factory(&fetcher_factory_);
g_browser_process->google_url_tracker()->infobar_creator_ =
&CreateTestInfobar;
}
void GoogleURLTrackerTest::TearDown() {
URLFetcher::set_factory(NULL);
TestingBrowserProcess* testing_browser_process =
static_cast<TestingBrowserProcess*>(g_browser_process);
testing_browser_process->SetGoogleURLTracker(NULL);
testing_browser_process->SetPrefService(NULL);
network_change_notifier_.reset();
delete io_thread_;
delete message_loop_;
}
TestURLFetcher* GoogleURLTrackerTest::GetFetcherByID(int expected_id) {
return fetcher_factory_.GetFetcherByID(expected_id);
}
void GoogleURLTrackerTest::MockSearchDomainCheckResponse(
int expected_id,
const std::string& domain) {
TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(expected_id);
if (!fetcher)
return;
fetcher->delegate()->OnURLFetchComplete(fetcher,
GURL(GoogleURLTracker::kSearchDomainCheckURL), net::URLRequestStatus(),
200, ResponseCookies(), domain);
// At this point, |fetcher| is deleted.
MessageLoop::current()->RunAllPending();
}
void GoogleURLTrackerTest::RequestServerCheck() {
if (!registrar_.IsRegistered(observer_.get(),
NotificationType::GOOGLE_URL_UPDATED,
NotificationService::AllSources())) {
registrar_.Add(observer_.get(), NotificationType::GOOGLE_URL_UPDATED,
NotificationService::AllSources());
}
GoogleURLTracker::RequestServerCheck();
MessageLoop::current()->RunAllPending();
}
void GoogleURLTrackerTest::FinishSleep() {
g_browser_process->google_url_tracker()->FinishSleep();
MessageLoop::current()->RunAllPending();
}
void GoogleURLTrackerTest::NotifyIPAddressChanged() {
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
MessageLoop::current()->RunAllPending();
}
GURL GoogleURLTrackerTest::GetFetchedGoogleURL() {
return g_browser_process->google_url_tracker()->fetched_google_url_;
}
void GoogleURLTrackerTest::SetGoogleURL(const GURL& url) {
g_browser_process->google_url_tracker()->google_url_ = url;
}
void GoogleURLTrackerTest::SetLastPromptedGoogleURL(const GURL& url) {
g_browser_process->local_state()->SetString(
prefs::kLastPromptedGoogleURL, url.spec());
}
GURL GoogleURLTrackerTest::GetLastPromptedGoogleURL() {
return GURL(g_browser_process->local_state()->GetString(
prefs::kLastPromptedGoogleURL));
}
void GoogleURLTrackerTest::SearchCommitted(const GURL& search_url) {
GoogleURLTracker* google_url_tracker =
g_browser_process->google_url_tracker();
google_url_tracker->SearchCommitted();
if (google_url_tracker->registrar_.IsRegistered(google_url_tracker,
NotificationType::NAV_ENTRY_PENDING,
NotificationService::AllSources()))
google_url_tracker->search_url_ = search_url;
}
void GoogleURLTrackerTest::NavEntryCommitted() {
GoogleURLTracker* google_url_tracker =
g_browser_process->google_url_tracker();
google_url_tracker->ShowGoogleURLInfoBarIfNecessary(NULL);
}
bool GoogleURLTrackerTest::InfoBarIsShown() {
return (g_browser_process->google_url_tracker()->infobar_ != NULL);
}
GURL GoogleURLTrackerTest::GetInfoBarShowingURL() {
TestInfoBarDelegate* infobar = static_cast<TestInfoBarDelegate*>(
g_browser_process->google_url_tracker()->infobar_);
return infobar->new_google_url();
}
void GoogleURLTrackerTest::AcceptGoogleURL() {
TestInfoBarDelegate* infobar = static_cast<TestInfoBarDelegate*>(
g_browser_process->google_url_tracker()->infobar_);
ASSERT_TRUE(infobar);
ASSERT_TRUE(infobar->google_url_tracker());
infobar->google_url_tracker()->AcceptGoogleURL(infobar->new_google_url());
}
void GoogleURLTrackerTest::CancelGoogleURL() {
TestInfoBarDelegate* infobar = static_cast<TestInfoBarDelegate*>(
g_browser_process->google_url_tracker()->infobar_);
ASSERT_TRUE(infobar);
ASSERT_TRUE(infobar->google_url_tracker());
infobar->google_url_tracker()->CancelGoogleURL(infobar->new_google_url());
}
void GoogleURLTrackerTest::InfoBarClosed() {
InfoBarDelegate* infobar = g_browser_process->google_url_tracker()->infobar_;
ASSERT_TRUE(infobar);
GoogleURLTracker* url_tracker =
static_cast<TestInfoBarDelegate*>(infobar)->google_url_tracker();
ASSERT_TRUE(url_tracker);
url_tracker->InfoBarClosed();
delete infobar;
}
void GoogleURLTrackerTest::ExpectDefaultURLs() {
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage),
GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL(), GetFetchedGoogleURL());
}
// Tests ----------------------------------------------------------------------
TEST_F(GoogleURLTrackerTest, DontFetchWhenNoOneRequestsCheck) {
ExpectDefaultURLs();
FinishSleep();
// No one called RequestServerCheck() so nothing should have happened.
EXPECT_FALSE(GetFetcherByID(0));
ExpectDefaultURLs();
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, UpdateOnFirstRun) {
RequestServerCheck();
EXPECT_FALSE(GetFetcherByID(0));
ExpectDefaultURLs();
EXPECT_FALSE(observer_->notified());
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
// GoogleURL should be updated, becase there was no last prompted URL.
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_TRUE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, DontUpdateWhenUnchanged) {
SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
RequestServerCheck();
EXPECT_FALSE(GetFetcherByID(0));
ExpectDefaultURLs();
EXPECT_FALSE(observer_->notified());
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
// GoogleURL should not be updated, because the fetched and prompted URLs
// match.
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage),
GoogleURLTracker::GoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, UpdatePromptedURLOnReturnToPreviousLocation) {
SetLastPromptedGoogleURL(GURL("http://www.google.co.jp/"));
SetGoogleURL(GURL("http://www.google.co.uk/"));
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, RefetchOnIPAddressChange) {
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_TRUE(observer_->notified());
observer_->clear_notified();
NotifyIPAddressChanged();
MockSearchDomainCheckResponse(1, ".google.co.in");
EXPECT_EQ(GURL("http://www.google.co.in/"), GetFetchedGoogleURL());
// Just fetching a new URL shouldn't reset things without a prompt.
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, DontRefetchWhenNoOneRequestsCheck) {
FinishSleep();
NotifyIPAddressChanged();
// No one called RequestServerCheck() so nothing should have happened.
EXPECT_FALSE(GetFetcherByID(0));
ExpectDefaultURLs();
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, FetchOnLateRequest) {
FinishSleep();
NotifyIPAddressChanged();
RequestServerCheck();
// The first request for a check should trigger a fetch if it hasn't happened
// already.
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_TRUE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, SearchingDoesNothingIfNoNeedToPrompt) {
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.uk");
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
EXPECT_TRUE(observer_->notified());
observer_->clear_notified();
SearchCommitted(GURL("http://www.google.co.uk/search?q=test"));
NavEntryCommitted();
EXPECT_FALSE(InfoBarIsShown());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetFetchedGoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, InfobarClosed) {
SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.jp");
SearchCommitted(GURL("http://www.google.co.uk/search?q=test"));
NavEntryCommitted();
EXPECT_TRUE(InfoBarIsShown());
InfoBarClosed();
EXPECT_FALSE(InfoBarIsShown());
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage),
GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, InfobarRefused) {
SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.jp");
SearchCommitted(GURL("http://www.google.co.uk/search?q=test"));
NavEntryCommitted();
EXPECT_TRUE(InfoBarIsShown());
CancelGoogleURL();
InfoBarClosed();
EXPECT_FALSE(InfoBarIsShown());
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage),
GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.jp/"), GetLastPromptedGoogleURL());
EXPECT_FALSE(observer_->notified());
}
TEST_F(GoogleURLTrackerTest, InfobarAccepted) {
SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
RequestServerCheck();
FinishSleep();
MockSearchDomainCheckResponse(0, ".google.co.jp");
SearchCommitted(GURL("http://www.google.co.uk/search?q=test"));
NavEntryCommitted();
EXPECT_TRUE(InfoBarIsShown());
AcceptGoogleURL();
InfoBarClosed();
EXPECT_FALSE(InfoBarIsShown());
EXPECT_EQ(GURL("http://www.google.co.jp/"), GoogleURLTracker::GoogleURL());
EXPECT_EQ(GURL("http://www.google.co.jp/"), GetLastPromptedGoogleURL());
EXPECT_TRUE(observer_->notified());
}