diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-12 07:42:00 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-12 07:42:00 +0000 |
commit | a7da401932bc46d304c646226aa565527bb945f9 (patch) | |
tree | 96f16aeab4e8e9cc5c26b52c76f3c4a0d4fb0271 | |
parent | cec5983338c93312e6a049ad31f028c25f7d6abc (diff) | |
download | chromium_src-a7da401932bc46d304c646226aa565527bb945f9.zip chromium_src-a7da401932bc46d304c646226aa565527bb945f9.tar.gz chromium_src-a7da401932bc46d304c646226aa565527bb945f9.tar.bz2 |
RLZTracker refactoring/cleanup
* Introduced separate RLZTrackerDelegate to provide test impl.
* API calls now simply schedule the task on SequencedWorkerPool
* acquire lock when clearing cache in ClearnupRlz
A few extra notes:
* I removed GetAccessPointRlz{On/NotOn}IoThread because
we no longer mix methods between threads.
* I reordered methods only in headers. I kept the order in .cc file
to make the reviewing easier. I'll reorder the method body in followup CL.
BUG=261377
Review URL: https://codereview.chromium.org/26771002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228333 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/rlz/rlz.cc | 206 | ||||
-rw-r--r-- | chrome/browser/rlz/rlz.h | 142 | ||||
-rw-r--r-- | chrome/browser/rlz/rlz_unittest.cc | 225 |
3 files changed, 279 insertions, 294 deletions
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc index 4aa8b5f5..dfad491 100644 --- a/chrome/browser/rlz/rlz.cc +++ b/chrome/browser/rlz/rlz.cc @@ -63,6 +63,10 @@ namespace { const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200); const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20); +// Tracker used for testing purposes only. If this value is non-NULL, it +// will be returned from GetInstance() instead of the regular singleton. +RLZTracker* tracker_for_test_ = NULL; + bool IsBrandOrganic(const std::string& brand) { return brand.empty() || google_util::IsOrganic(brand); } @@ -131,26 +135,6 @@ void RecordProductEvents(bool first_run, } } -bool SendFinancialPing(const std::string& brand, - const string16& lang, - const string16& referral) { - rlz_lib::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX, - RLZTracker::CHROME_HOME_PAGE, - rlz_lib::NO_ACCESS_POINT}; - std::string lang_ascii(UTF16ToASCII(lang)); - std::string referral_ascii(UTF16ToASCII(referral)); - std::string product_signature; -#if defined(OS_CHROMEOS) - product_signature = "chromeos"; -#else - product_signature = "chrome"; -#endif - return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, - product_signature.c_str(), - brand.c_str(), referral_ascii.c_str(), - lang_ascii.c_str(), false, true); -} - } // namespace #if defined(OS_WIN) @@ -176,11 +160,9 @@ const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE = rlz_lib::CHROMEOS_HOME_PAGE; #endif -RLZTracker* RLZTracker::tracker_ = NULL; - // static RLZTracker* RLZTracker::GetInstance() { - return tracker_ ? tracker_ : Singleton<RLZTracker>::get(); + return tracker_for_test_ ? tracker_for_test_ : Singleton<RLZTracker>::get(); } RLZTracker::RLZTracker() @@ -193,6 +175,21 @@ RLZTracker::RLZTracker() already_ran_(false), omnibox_used_(false), homepage_used_(false), + delegate_(this), + min_init_delay_(kMinInitDelay) { +} + +RLZTracker::RLZTracker(RLZTrackerDelegate* delegate) + : first_run_(false), + send_ping_immediately_(false), + is_google_default_search_(false), + is_google_homepage_(false), + is_google_in_startpages_(false), + worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()), + already_ran_(false), + omnibox_used_(false), + homepage_used_(false), + delegate_(delegate), min_init_delay_(kMinInitDelay) { } @@ -255,6 +252,11 @@ bool RLZTracker::InitRlzFromProfileDelayed(Profile* profile, return true; } +// static +void RLZTracker::SetTrackerForTest(RLZTracker* tracker) { + tracker_for_test_ = tracker; +} + bool RLZTracker::Init(bool first_run, bool send_ping_immediately, base::TimeDelta delay, @@ -310,6 +312,7 @@ void RLZTracker::ScheduleDelayedInit(base::TimeDelta delay) { void RLZTracker::DelayedInit() { bool schedule_ping = false; + DCHECK(!already_ran_); // For organic brandcodes do not use rlz at all. Empty brandcode usually // means a chromium install. This is ok. @@ -333,19 +336,19 @@ void RLZTracker::DelayedInit() { already_ran_ = true; if (schedule_ping) - ScheduleFinancialPing(); + ScheduleSendFinancialPing(); } -void RLZTracker::ScheduleFinancialPing() { +void RLZTracker::ScheduleSendFinancialPing() { BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( worker_pool_token_, FROM_HERE, - base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)), + base::Bind(&RLZTracker::SendFinancialPingNow, base::Unretained(this)), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); } -void RLZTracker::PingNowImpl() { - TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl"); +void RLZTracker::SendFinancialPingNow() { + TRACE_EVENT0("RLZ", "RLZTracker::SendFinancialPingNow"); string16 lang; GoogleUpdateSettings::GetLanguage(&lang); if (lang.empty()) @@ -353,7 +356,8 @@ void RLZTracker::PingNowImpl() { string16 referral; GoogleUpdateSettings::GetReferral(&referral); - if (!IsBrandOrganic(brand_) && SendFinancialPing(brand_, lang, referral)) { + if (!IsBrandOrganic(brand_) && + delegate_->SendFinancialPing(brand_, lang, referral)) { GoogleUpdateSettings::ClearReferral(); { @@ -368,14 +372,28 @@ void RLZTracker::PingNowImpl() { if (!IsBrandOrganic(reactivation_brand_)) { rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str()); - SendFinancialPing(reactivation_brand_, lang, referral); + delegate_->SendFinancialPing(reactivation_brand_, lang, referral); } } bool RLZTracker::SendFinancialPing(const std::string& brand, const string16& lang, const string16& referral) { - return ::SendFinancialPing(brand, lang, referral); + rlz_lib::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX, + RLZTracker::CHROME_HOME_PAGE, + rlz_lib::NO_ACCESS_POINT}; + std::string lang_ascii(UTF16ToASCII(lang)); + std::string referral_ascii(UTF16ToASCII(referral)); + std::string product_signature; +#if defined(OS_CHROMEOS) + product_signature = "chromeos"; +#else + product_signature = "chrome"; +#endif + return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, + product_signature.c_str(), + brand.c_str(), referral_ascii.c_str(), + lang_ascii.c_str(), false, true); } void RLZTracker::Observe(int type, @@ -383,7 +401,7 @@ void RLZTracker::Observe(int type, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: - RecordFirstSearch(CHROME_OMNIBOX); + ScheduleRecordFirstSearch(CHROME_OMNIBOX); registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, content::NotificationService::AllSources()); break; @@ -393,7 +411,7 @@ void RLZTracker::Observe(int type, if (entry != NULL && ((entry->GetTransitionType() & content::PAGE_TRANSITION_HOME_PAGE) != 0)) { - RecordFirstSearch(CHROME_HOME_PAGE); + ScheduleRecordFirstSearch(CHROME_HOME_PAGE); registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, content::NotificationService::AllSources()); } @@ -406,20 +424,15 @@ void RLZTracker::Observe(int type, } // static -bool RLZTracker::RecordProductEvent(rlz_lib::Product product, +void RLZTracker::RecordProductEvent(rlz_lib::Product product, rlz_lib::AccessPoint point, rlz_lib::Event event_id) { - return GetInstance()->RecordProductEventImpl(product, point, event_id); + GetInstance()->ScheduleRecordProductEvent(product, point, event_id); } bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product, rlz_lib::AccessPoint point, rlz_lib::Event event_id) { - // Make sure we don't access disk outside of the I/O thread. - // In such case we repost the task on the right thread and return error. - if (ScheduleRecordProductEvent(product, point, event_id)) - return true; - bool ret = rlz_lib::RecordProductEvent(product, point, event_id); // If chrome has been reactivated, record the event for this brand as well. @@ -427,53 +440,40 @@ bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product, rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str()); ret &= rlz_lib::RecordProductEvent(product, point, event_id); } - return ret; } -bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product, +void RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product, rlz_lib::AccessPoint point, rlz_lib::Event event_id) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) - return false; - BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( worker_pool_token_, FROM_HERE, - base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent), + base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEventImpl), + base::Unretained(this), product, point, event_id), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); - - return true; } -void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) { - // Make sure we don't access disk outside of the I/O thread. - // In such case we repost the task on the right thread and return error. - if (ScheduleRecordFirstSearch(point)) - return; - +void RLZTracker::RecordFirstSearchImpl(rlz_lib::AccessPoint point) { bool* record_used = point == CHROME_OMNIBOX ? &omnibox_used_ : &homepage_used_; // Try to record event now, else set the flag to try later when we // attempt the ping. - if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH)) + if (!RecordProductEventImpl(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH)) *record_used = true; else if (send_ping_immediately_ && point == CHROME_OMNIBOX) ScheduleDelayedInit(base::TimeDelta()); } -bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) - return false; +void RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) { BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( worker_pool_token_, FROM_HERE, - base::Bind(&RLZTracker::RecordFirstSearch, + base::Bind(&RLZTracker::RecordFirstSearchImpl, base::Unretained(this), point), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); - return true; } // static @@ -491,94 +491,88 @@ std::string RLZTracker::GetAccessPointHttpHeader(rlz_lib::AccessPoint point) { return extra_headers; } -// GetAccessPointRlz() caches RLZ strings for all access points. If we had -// a successful ping, then we update the cached value. +bool RLZTracker::GetCachedAccessPointRlz(rlz_lib::AccessPoint point, + string16* rlz) { + base::AutoLock lock(cache_lock_); + if (rlz_cache_.find(point) != rlz_cache_.end()) { + if (rlz) + *rlz = rlz_cache_[point]; + return true; + } + return false; +} + +// static bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, string16* rlz) { TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointRlz"); - return GetInstance()->GetAccessPointRlzImpl(point, rlz); -} - -// GetAccessPointRlz() caches RLZ strings for all access points. If we had -// a successful ping, then we update the cached value. -bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point, - string16* rlz) { - // If the RLZ string for the specified access point is already cached, - // simply return its value. - { - base::AutoLock lock(cache_lock_); - if (rlz_cache_.find(point) != rlz_cache_.end()) { - if (rlz) - *rlz = rlz_cache_[point]; - return true; - } - } + RLZTracker* tracker = GetInstance(); + if (tracker->GetCachedAccessPointRlz(point, rlz)) + return true; - // Make sure we don't access disk outside of the I/O thread. - // In such case we repost the task on the right thread and return error. - if (ScheduleGetAccessPointRlz(point)) - return false; + // GetAccessPointRlzImpl() caches RLZ strings for all access points. If we had + // a successful ping, then we update the cached value. + tracker->ScheduleGetAccessPointRlz(point); + return false; +} +void RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point) { + string16* rlz_not_used = NULL; + if (GetCachedAccessPointRlz(point, rlz_not_used)) + return; char str_rlz[rlz_lib::kMaxRlzLength + 1]; if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength)) - return false; + return; string16 rlz_local(ASCIIToUTF16(std::string(str_rlz))); - if (rlz) - *rlz = rlz_local; - base::AutoLock lock(cache_lock_); rlz_cache_[point] = rlz_local; - return true; + return; } -bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) - return false; - - string16* not_used = NULL; +void RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) { BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( worker_pool_token_, FROM_HERE, - base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point, - not_used), + base::Bind(&RLZTracker::GetAccessPointRlzImpl, + base::Unretained(this), point), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); - return true; } #if defined(OS_CHROMEOS) // static void RLZTracker::ClearRlzState() { - GetInstance()->ClearRlzStateImpl(); + GetInstance()->ScheduleClearRlzState(); } void RLZTracker::ClearRlzStateImpl() { - if (ScheduleClearRlzState()) - return; rlz_lib::ClearAllProductEvents(rlz_lib::CHROME); } -bool RLZTracker::ScheduleClearRlzState() { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) - return false; - +void RLZTracker::ScheduleClearRlzState() { BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( worker_pool_token_, FROM_HERE, base::Bind(&RLZTracker::ClearRlzStateImpl, base::Unretained(this)), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); - return true; } #endif // static void RLZTracker::CleanupRlz() { - GetInstance()->rlz_cache_.clear(); - GetInstance()->registrar_.RemoveAll(); + GetInstance()->Cleanup(); rlz_lib::SetURLRequestContext(NULL); } +void RLZTracker::Cleanup() { + { + base::AutoLock lock(cache_lock_); + rlz_cache_.clear(); + } + registrar_.RemoveAll(); +} + // static void RLZTracker::EnableZeroDelayForTesting() { GetInstance()->min_init_delay_ = base::TimeDelta(); diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h index d55e05c1..517bb7d 100644 --- a/chrome/browser/rlz/rlz.h +++ b/chrome/browser/rlz/rlz.h @@ -13,6 +13,7 @@ #include <string> #include "base/basictypes.h" +#include "base/gtest_prod_util.h" #include "base/memory/singleton.h" #include "base/strings/string16.h" #include "base/threading/sequenced_worker_pool.h" @@ -26,6 +27,16 @@ namespace net { class URLRequestContextGetter; } +// An interface to provide financial ping implementation. +class RLZTrackerDelegate { + public: + // Sends the financial ping to the RLZ servers. This method is virtual to + // allow tests to override. + virtual bool SendFinancialPing(const std::string& brand, + const string16& lang, + const string16& referral) = 0; +}; + // RLZ is a library which is used to measure distribution scenarios. // Its job is to record certain lifetime events in the registry and to send // them encoded as a compact string at most twice. The sent data does @@ -35,8 +46,8 @@ class URLRequestContextGetter; // // For partner or bundled installs, the RLZ might send more information // according to the terms disclosed in the EULA. - -class RLZTracker : public content::NotificationObserver { +class RLZTracker : public content::NotificationObserver, + public RLZTrackerDelegate { public: // Initializes the RLZ library services for use in chrome. Schedules a delayed // task that performs the ping and registers some events when 'first-run' is @@ -53,9 +64,8 @@ class RLZTracker : public content::NotificationObserver { base::TimeDelta delay); // Records an RLZ event. Some events can be access point independent. - // Returns false it the event could not be recorded. Requires write access - // to the HKCU registry hive on windows. - static bool RecordProductEvent(rlz_lib::Product product, + // Requires write access to the HKCU registry hive on windows. + static void RecordProductEvent(rlz_lib::Product product, rlz_lib::AccessPoint point, rlz_lib::Event event_id); @@ -90,11 +100,15 @@ class RLZTracker : public content::NotificationObserver { // Enables zero delay for InitRlzFromProfileDelayed. For testing only. static void EnableZeroDelayForTesting(); - // The following methods are made protected so that they can be used for - // testing purposes. Production code should never need to call these. - protected: - RLZTracker(); - virtual ~RLZTracker(); + private: + friend class RlzLibTest; + friend class TestRLZTrackerDelegate; + friend class base::RefCountedThreadSafe<RLZTracker>; + friend struct DefaultSingletonTraits<RLZTracker>; + + FRIEND_TEST_ALL_PREFIXES(RlzLibTest, GetAccessPointRlzIsCached); + FRIEND_TEST_ALL_PREFIXES(RlzLibTest, ObserveHandlesBadArgs); + FRIEND_TEST_ALL_PREFIXES(RlzLibTest, PingUpdatesRlzCache); // Called by InitRlzFromProfileDelayed with values taken from |profile|. static bool InitRlzDelayed(bool first_run, @@ -104,29 +118,22 @@ class RLZTracker : public content::NotificationObserver { bool is_google_homepage, bool is_google_in_startpages); - // Performs initialization of RLZ tracker that is purposefully delayed so - // that it does not interfere with chrome startup time. - virtual void DelayedInit(); - - // content::NotificationObserver implementation: - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - // Used by test code to override the default RLZTracker instance returned // by GetInstance(). - void set_tracker(RLZTracker* tracker) { - tracker_ = tracker; - } + static void SetTrackerForTest(RLZTracker* tracker); + + RLZTracker(); + explicit RLZTracker(RLZTrackerDelegate* delegate); + virtual ~RLZTracker(); + + // Performs initialization of RLZ tracker that is purposefully delayed so + // that it does not interfere with chrome startup time. + void DelayedInit(); // Sends the financial ping to the RLZ servers and invalidates the RLZ string // cache since the response from the RLZ server may have changed then. // Protected so that its accessible from tests. - void PingNowImpl(); - - private: - friend struct DefaultSingletonTraits<RLZTracker>; - friend class base::RefCountedThreadSafe<RLZTracker>; + void SendFinancialPingNow(); // Implementation called from InitRlzDelayed() static method. bool Init(bool first_run, @@ -136,59 +143,69 @@ class RLZTracker : public content::NotificationObserver { bool google_default_homepage, bool is_google_in_startpages); - // Implementation called from RecordProductEvent() static method. - bool RecordProductEventImpl(rlz_lib::Product product, - rlz_lib::AccessPoint point, - rlz_lib::Event event_id); - - // Records FIRST_SEARCH event. Called from Observe() on blocking task runner. - void RecordFirstSearch(rlz_lib::AccessPoint point); + // Gets the cached accesspoint rlz. Returns false if the cache doesn't exist. + bool GetCachedAccessPointRlz(rlz_lib::AccessPoint point, string16* rlz); - // Implementation called from GetAccessPointRlz() static method. - bool GetAccessPointRlzImpl(rlz_lib::AccessPoint point, string16* rlz); +#if defined(OS_CHROMEOS) + // Implementation called from ClearRlzState static method. + void ClearRlzStateImpl(); +#endif // Schedules the delayed initialization. This method is virtual to allow // tests to override how the scheduling is done. - virtual void ScheduleDelayedInit(base::TimeDelta delay); + void ScheduleDelayedInit(base::TimeDelta delay); // Schedules a call to rlz_lib::RecordProductEvent(). This method is virtual // to allow tests to override how the scheduling is done. - virtual bool ScheduleRecordProductEvent(rlz_lib::Product product, - rlz_lib::AccessPoint point, - rlz_lib::Event event_id); - + void ScheduleRecordProductEvent(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id); // Schedules a call to rlz_lib::RecordFirstSearch(). This method is virtual // to allow tests to override how the scheduling is done. - virtual bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point); + void ScheduleRecordFirstSearch(rlz_lib::AccessPoint point); // Schedules a call to rlz_lib::SendFinancialPing(). This method is virtual // to allow tests to override how the scheduling is done. - virtual void ScheduleFinancialPing(); + void ScheduleSendFinancialPing(); // Schedules a call to GetAccessPointRlz() on the I/O thread if the current // thread is not already the I/O thread, otherwise does nothing. Returns // true if the call was scheduled, and false otherwise. This method is // virtual to allow tests to override how the scheduling is done. - virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point); + void ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point); - // Sends the financial ping to the RLZ servers. This method is virtual to - // allow tests to override. - virtual bool SendFinancialPing(const std::string& brand, - const string16& lang, - const string16& referral); #if defined(OS_CHROMEOS) - // Implementation called from ClearRlzState static method. - void ClearRlzStateImpl(); - - // Schedules a call to ClearRlzStateImpl(). This method is virtual - // to allow tests to override how the scheduling is done. - virtual bool ScheduleClearRlzState(); + // Schedules a call to ClearRlzStateImpl(). + void ScheduleClearRlzState(); #endif - // Tracker used for testing purposes only. If this value is non-NULL, it - // will be returned from GetInstance() instead of the regular singleton. - static RLZTracker* tracker_; + // Implementation called from RecordProductEvent() static method + // on SequencedWorkerPool. + bool RecordProductEventImpl(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id); + + // Records FIRST_SEARCH event. Scheduled on SequencedWorkerPool + // in Observe. + void RecordFirstSearchImpl(rlz_lib::AccessPoint point); + + // Implementation of GetAccessPointRlz() invoked on SequencedWorkerPool. + // This caches RLZ strings for all access points. If we had + // a successful ping, then we update the cached value. + void GetAccessPointRlzImpl(rlz_lib::AccessPoint point); + + void Cleanup(); + + // Overridden from RZLTrackerDelegate: + virtual bool SendFinancialPing(const std::string& brand, + const string16& lang, + const string16& referral) OVERRIDE; + + // content::NotificationObserver implementation: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; // Configuation data for RLZ tracker. Set by call to Init(). bool first_run_; @@ -205,9 +222,10 @@ class RLZTracker : public content::NotificationObserver { // initialization. bool already_ran_; - // Keeps a cache of RLZ access point strings, since they rarely change. - // The cache must be protected by a lock since it may be accessed from - // the UI thread for reading and the IO thread for reading and/or writing. + // Keeps a cache of RLZ access point strings, since they rarely + // change. The cache must be protected by a lock since it may be + // accessed from the UI thread for reading and the global blocking + // pool for reading and/or writing. base::Lock cache_lock_; std::map<rlz_lib::AccessPoint, string16> rlz_cache_; @@ -221,6 +239,8 @@ class RLZTracker : public content::NotificationObserver { content::NotificationRegistrar registrar_; + RLZTrackerDelegate* delegate_; // not owned. + // Minimum delay before sending financial ping after initialization. base::TimeDelta min_init_delay_; diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc index 0726ce2..311d11c 100644 --- a/chrome/browser/rlz/rlz_unittest.cc +++ b/chrome/browser/rlz/rlz_unittest.cc @@ -18,6 +18,7 @@ #include "chrome/common/env_vars.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" @@ -90,64 +91,29 @@ AssertionResult CmpHelperSTRNC(const char* str_expression, #define EXPECT_STR_NOT_CONTAIN(str, substr) \ EXPECT_PRED_FORMAT2(CmpHelperSTRNC, str, substr) +void RunPendingTasks() { + content::BrowserThread::GetBlockingPool()->FlushForTesting(); +} + } // namespace -// Test class for RLZ tracker. Makes some member functions public and -// overrides others to make it easier to test. -class TestRLZTracker : public RLZTracker { +// Test RLZTrackerDelegate that implements test specific +// SendFinalcialPing and provides a way to verify it works. +class TestRLZTrackerDelegate : public RLZTrackerDelegate { public: - using RLZTracker::InitRlzDelayed; - using RLZTracker::DelayedInit; - using RLZTracker::Observe; - - TestRLZTracker() : assume_not_ui_thread_(true) { - set_tracker(this); + TestRLZTrackerDelegate() : tracker_(this) { + RLZTracker::SetTrackerForTest(&tracker_); } - virtual ~TestRLZTracker() { - set_tracker(NULL); + virtual ~TestRLZTrackerDelegate() { + RLZTracker::SetTrackerForTest(NULL); } bool was_ping_sent_for_brand(const std::string& brand) const { return pinged_brands_.count(brand) > 0; } - void set_assume_not_ui_thread(bool assume_not_ui_thread) { - assume_not_ui_thread_ = assume_not_ui_thread; - } - private: - virtual void ScheduleDelayedInit(base::TimeDelta delay) OVERRIDE { - // If the delay is 0, invoke the delayed init now. Otherwise, - // don't schedule anything, it will be manually called during tests. - if (delay == base::TimeDelta()) - DelayedInit(); - } - - virtual void ScheduleFinancialPing() OVERRIDE { - PingNowImpl(); - } - - virtual bool ScheduleRecordProductEvent(rlz_lib::Product product, - rlz_lib::AccessPoint point, - rlz_lib::Event event_id) OVERRIDE { - return !assume_not_ui_thread_; - } - - virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) OVERRIDE { - return !assume_not_ui_thread_; - } - - virtual bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) OVERRIDE { - return !assume_not_ui_thread_; - } - -#if defined(OS_CHROMEOS) - virtual bool ScheduleClearRlzState() OVERRIDE { - return !assume_not_ui_thread_; - } -#endif - virtual bool SendFinancialPing(const std::string& brand, const string16& lang, const string16& referral) OVERRIDE { @@ -165,9 +131,9 @@ class TestRLZTracker : public RLZTracker { } std::set<std::string> pinged_brands_; - bool assume_not_ui_thread_; + RLZTracker tracker_; - DISALLOW_COPY_AND_ASSIGN(TestRLZTracker); + DISALLOW_COPY_AND_ASSIGN(TestRLZTrackerDelegate); }; class RlzLibTest : public testing::Test { @@ -190,7 +156,24 @@ class RlzLibTest : public testing::Test { void ExpectRlzPingSent(bool expected); void ExpectReactivationRlzPingSent(bool expected); - TestRLZTracker tracker_; + bool InitRlzDelayed(bool first_run, + bool send_ping_immediately, + base::TimeDelta delay, + bool is_google_default_search, + bool is_google_homepage, + bool is_google_in_startpages) { + bool ret = RLZTracker::InitRlzDelayed( + first_run, + send_ping_immediately, + delay, + is_google_default_search, + is_google_homepage, + is_google_in_startpages); + RunPendingTasks(); + return ret; + } + + TestRLZTrackerDelegate tracker_; #if defined(OS_WIN) RegistryOverrideManager override_manager_; #elif defined(OS_POSIX) @@ -289,22 +272,26 @@ void RlzLibTest::SetRegistryBrandValue(const wchar_t* name, #endif void RlzLibTest::SimulateOmniboxUsage() { - tracker_.Observe(chrome::NOTIFICATION_OMNIBOX_OPENED_URL, - content::NotificationService::AllSources(), - content::Details<OmniboxLog>(NULL)); + RLZTracker::GetInstance()->Observe( + chrome::NOTIFICATION_OMNIBOX_OPENED_URL, + content::NotificationService::AllSources(), + content::Details<OmniboxLog>(NULL)); + RunPendingTasks(); } void RlzLibTest::SimulateHomepageUsage() { scoped_ptr<NavigationEntry> entry(NavigationEntry::Create()); entry->SetPageID(0); entry->SetTransitionType(content::PAGE_TRANSITION_HOME_PAGE); - tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING, - content::NotificationService::AllSources(), - content::Details<NavigationEntry>(entry.get())); + RLZTracker::GetInstance()->Observe( + content::NOTIFICATION_NAV_ENTRY_PENDING, + content::NotificationService::AllSources(), + content::Details<NavigationEntry>(entry.get())); + RunPendingTasks(); } void RlzLibTest::InvokeDelayedInit() { - tracker_.DelayedInit(); + RLZTracker::GetInstance()->DelayedInit(); } void RlzLibTest::ExpectEventRecorded(const char* event_name, bool expected) { @@ -393,12 +380,13 @@ const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(20); TEST_F(RlzLibTest, RecordProductEvent) { RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::CHROME_OMNIBOX, rlz_lib::FIRST_SEARCH); + RunPendingTasks(); ExpectEventRecorded(kOmniboxFirstSearch, true); } TEST_F(RlzLibTest, QuickStopAfterStart) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, true); + InitRlzDelayed(true, false, kDelay, true, true, true); // Omnibox events. ExpectEventRecorded(kOmniboxInstall, false); @@ -414,7 +402,7 @@ TEST_F(RlzLibTest, QuickStopAfterStart) { } TEST_F(RlzLibTest, DelayedInitOnly) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); // Omnibox events. @@ -431,7 +419,7 @@ TEST_F(RlzLibTest, DelayedInitOnly) { } TEST_F(RlzLibTest, DelayedInitOnlyGoogleAsStartup) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, true); + InitRlzDelayed(true, false, kDelay, false, false, true); InvokeDelayedInit(); // Omnibox events. @@ -448,7 +436,7 @@ TEST_F(RlzLibTest, DelayedInitOnlyGoogleAsStartup) { } TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStrings) { - TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, false); + InitRlzDelayed(false, false, kDelay, true, true, false); InvokeDelayedInit(); // Omnibox events. @@ -465,7 +453,7 @@ TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStrings) { } TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStringsGoogleAsStartup) { - TestRLZTracker::InitRlzDelayed(false, false, kDelay, false, false, true); + InitRlzDelayed(false, false, kDelay, false, false, true); InvokeDelayedInit(); // Omnibox events. @@ -487,7 +475,7 @@ TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRun) { rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString); rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, kHomepageRlzString); - TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, true); + InitRlzDelayed(false, false, kDelay, true, true, true); InvokeDelayedInit(); // Omnibox events. @@ -504,7 +492,7 @@ TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRun) { } TEST_F(RlzLibTest, DelayedInitOnlyNoGoogleDefaultSearchOrHomepageOrStartup) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, false); + InitRlzDelayed(true, false, kDelay, false, false, false); InvokeDelayedInit(); // Omnibox events. @@ -521,7 +509,7 @@ TEST_F(RlzLibTest, DelayedInitOnlyNoGoogleDefaultSearchOrHomepageOrStartup) { } TEST_F(RlzLibTest, OmniboxUsageOnly) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); SimulateOmniboxUsage(); // Omnibox events. @@ -538,7 +526,7 @@ TEST_F(RlzLibTest, OmniboxUsageOnly) { } TEST_F(RlzLibTest, HomepageUsageOnly) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); SimulateHomepageUsage(); // Omnibox events. @@ -555,7 +543,7 @@ TEST_F(RlzLibTest, HomepageUsageOnly) { } TEST_F(RlzLibTest, UsageBeforeDelayedInit) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); SimulateOmniboxUsage(); SimulateHomepageUsage(); InvokeDelayedInit(); @@ -574,7 +562,7 @@ TEST_F(RlzLibTest, UsageBeforeDelayedInit) { } TEST_F(RlzLibTest, OmniboxUsageAfterDelayedInit) { - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); SimulateOmniboxUsage(); SimulateHomepageUsage(); @@ -593,7 +581,7 @@ TEST_F(RlzLibTest, OmniboxUsageAfterDelayedInit) { } TEST_F(RlzLibTest, OmniboxUsageSendsPingWhenSendPingImmediately) { - TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false); + InitRlzDelayed(true, true, kDelay, true, true, false); SimulateOmniboxUsage(); // Omnibox events. @@ -610,7 +598,7 @@ TEST_F(RlzLibTest, OmniboxUsageSendsPingWhenSendPingImmediately) { } TEST_F(RlzLibTest, HomepageUsageDoesNotSendPingWhenSendPingImmediately) { - TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false); + InitRlzDelayed(true, true, kDelay, true, true, false); SimulateHomepageUsage(); // Omnibox events. @@ -627,7 +615,7 @@ TEST_F(RlzLibTest, HomepageUsageDoesNotSendPingWhenSendPingImmediately) { } TEST_F(RlzLibTest, StartupUsageDoesNotSendPingWhenSendPingImmediately) { - TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, false, true); + InitRlzDelayed(true, true, kDelay, true, false, true); SimulateHomepageUsage(); // Omnibox events. @@ -643,42 +631,18 @@ TEST_F(RlzLibTest, StartupUsageDoesNotSendPingWhenSendPingImmediately) { ExpectRlzPingSent(false); } -TEST_F(RlzLibTest, GetAccessPointRlzOnIoThread) { - // Set dummy RLZ string. - rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString); - - string16 rlz; - - tracker_.set_assume_not_ui_thread(true); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); - EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); -} - -TEST_F(RlzLibTest, GetAccessPointRlzNotOnIoThread) { - // Set dummy RLZ string. - rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString); - - string16 rlz; - - tracker_.set_assume_not_ui_thread(false); - EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); -} - TEST_F(RlzLibTest, GetAccessPointRlzIsCached) { // Set dummy RLZ string. rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString); string16 rlz; - - tracker_.set_assume_not_ui_thread(false); + RLZTracker* tracker = RLZTracker::GetInstance(); + EXPECT_FALSE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); - - tracker_.set_assume_not_ui_thread(true); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); - EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); - - tracker_.set_assume_not_ui_thread(false); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); + RunPendingTasks(); + EXPECT_TRUE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); } @@ -690,36 +654,40 @@ TEST_F(RlzLibTest, PingUpdatesRlzCache) { string16 rlz; // Prime the cache. - tracker_.set_assume_not_ui_thread(true); - + EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); + RunPendingTasks(); EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); + EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz( - RLZTracker::CHROME_HOME_PAGE, &rlz)); + + EXPECT_FALSE( + RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz)); + RunPendingTasks(); + EXPECT_TRUE( + RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz)); EXPECT_STREQ(kHomepageRlzString, UTF16ToUTF8(rlz).c_str()); // Make sure cache is valid. - tracker_.set_assume_not_ui_thread(false); - - EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); + RLZTracker* tracker = RLZTracker::GetInstance(); + EXPECT_TRUE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz( - RLZTracker::CHROME_HOME_PAGE, &rlz)); + EXPECT_TRUE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz)); EXPECT_STREQ(kHomepageRlzString, UTF16ToUTF8(rlz).c_str()); // Perform ping. - tracker_.set_assume_not_ui_thread(true); - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); + RunPendingTasks(); ExpectRlzPingSent(true); // Make sure cache is now updated. - tracker_.set_assume_not_ui_thread(false); - - EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); + EXPECT_TRUE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz)); EXPECT_STREQ(kNewOmniboxRlzString, UTF16ToUTF8(rlz).c_str()); - EXPECT_TRUE(RLZTracker::GetAccessPointRlz( - RLZTracker::CHROME_HOME_PAGE, &rlz)); + EXPECT_TRUE( + tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz)); EXPECT_STREQ(kNewHomepageRlzString, UTF16ToUTF8(rlz).c_str()); } @@ -727,12 +695,14 @@ TEST_F(RlzLibTest, ObserveHandlesBadArgs) { scoped_ptr<NavigationEntry> entry(NavigationEntry::Create()); entry->SetPageID(0); entry->SetTransitionType(content::PAGE_TRANSITION_LINK); - tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING, - content::NotificationService::AllSources(), - content::Details<NavigationEntry>(NULL)); - tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING, - content::NotificationService::AllSources(), - content::Details<NavigationEntry>(entry.get())); + RLZTracker::GetInstance()->Observe( + content::NOTIFICATION_NAV_ENTRY_PENDING, + content::NotificationService::AllSources(), + content::Details<NavigationEntry>(NULL)); + RLZTracker::GetInstance()->Observe( + content::NOTIFICATION_NAV_ENTRY_PENDING, + content::NotificationService::AllSources(), + content::Details<NavigationEntry>(entry.get())); } // TODO(thakis): Reactivation doesn't exist on Mac yet. @@ -740,7 +710,7 @@ TEST_F(RlzLibTest, ObserveHandlesBadArgs) { TEST_F(RlzLibTest, ReactivationNonOrganicNonOrganic) { SetReactivationBrand("REAC"); - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); ExpectRlzPingSent(true); @@ -751,7 +721,7 @@ TEST_F(RlzLibTest, ReactivationOrganicNonOrganic) { SetMainBrand("GGLS"); SetReactivationBrand("REAC"); - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); ExpectRlzPingSent(false); @@ -762,7 +732,7 @@ TEST_F(RlzLibTest, ReactivationNonOrganicOrganic) { SetMainBrand("TEST"); SetReactivationBrand("GGLS"); - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); ExpectRlzPingSent(true); @@ -773,7 +743,7 @@ TEST_F(RlzLibTest, ReactivationOrganicOrganic) { SetMainBrand("GGLS"); SetReactivationBrand("GGRS"); - TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InitRlzDelayed(true, false, kDelay, true, true, false); InvokeDelayedInit(); ExpectRlzPingSent(false); @@ -785,10 +755,11 @@ TEST_F(RlzLibTest, ReactivationOrganicOrganic) { TEST_F(RlzLibTest, ClearRlzState) { RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::CHROME_OMNIBOX, rlz_lib::FIRST_SEARCH); - + RunPendingTasks(); ExpectEventRecorded(kOmniboxFirstSearch, true); RLZTracker::ClearRlzState(); + RunPendingTasks(); ExpectEventRecorded(kOmniboxFirstSearch, false); } |