summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-12 07:42:00 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-12 07:42:00 +0000
commita7da401932bc46d304c646226aa565527bb945f9 (patch)
tree96f16aeab4e8e9cc5c26b52c76f3c4a0d4fb0271
parentcec5983338c93312e6a049ad31f028c25f7d6abc (diff)
downloadchromium_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.cc206
-rw-r--r--chrome/browser/rlz/rlz.h142
-rw-r--r--chrome/browser/rlz/rlz_unittest.cc225
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);
}