diff options
Diffstat (limited to 'components/rlz')
| -rw-r--r-- | components/rlz/BUILD.gn | 42 | ||||
| -rw-r--r-- | components/rlz/DEPS | 10 | ||||
| -rw-r--r-- | components/rlz/OWNERS | 4 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker.cc | 529 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker.h | 242 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_chromeos.cc | 24 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_delegate.cc | 15 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_delegate.h | 86 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_ios.cc | 19 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_mac.cc | 24 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_unittest.cc | 1009 | ||||
| -rw-r--r-- | components/rlz/rlz_tracker_win.cc | 24 |
12 files changed, 2028 insertions, 0 deletions
diff --git a/components/rlz/BUILD.gn b/components/rlz/BUILD.gn new file mode 100644 index 0000000..85608322 --- /dev/null +++ b/components/rlz/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright 2015 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. + +source_set("rlz") { + sources = [ + "rlz_tracker.cc", + "rlz_tracker.h", + "rlz_tracker_chromeos.cc", + "rlz_tracker_delegate.h", + "rlz_tracker_ios.cc", + "rlz_tracker_mac.cc", + "rlz_tracker_win.cc", + ] + + deps = [ + "//base", + "//components/google/core/browser", + "//net", + "//rlz:rlz_lib", + ] + + if (is_ios) { + deps = [ + "//ui/base", + ] + } +} + +source_set("unit_tests") { + testonly = true + sources = [ + "rlz_tracker_unittest.cc", + ] + + deps = [ + "//net:test_support", + "//rlz:test_support", + "//ui/base", + ":rlz", + ] +} diff --git a/components/rlz/DEPS b/components/rlz/DEPS new file mode 100644 index 0000000..a5d3e8a --- /dev/null +++ b/components/rlz/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + "+base", + "+components/google", + "+net", + "+rlz", + "+ui/base", + + # rlz is used on iOS. + "-content", +] diff --git a/components/rlz/OWNERS b/components/rlz/OWNERS new file mode 100644 index 0000000..d1986d9 --- /dev/null +++ b/components/rlz/OWNERS @@ -0,0 +1,4 @@ +cpu@chromium.org +gwilson@chromium.org +rogerta@chromium.org + diff --git a/components/rlz/rlz_tracker.cc b/components/rlz/rlz_tracker.cc new file mode 100644 index 0000000..baa166a --- /dev/null +++ b/components/rlz/rlz_tracker.cc @@ -0,0 +1,529 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This code glues the RLZ library DLL with Chrome. It allows Chrome to work +// with or without the DLL being present. If the DLL is not present the +// functions do nothing and just return false. + +#include "components/rlz/rlz_tracker.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/trace_event/trace_event.h" +#include "components/rlz/rlz_tracker_delegate.h" +#include "net/http/http_util.h" + +namespace rlz { +namespace { + +// Maximum and minimum delay for financial ping we would allow to be set through +// master preferences. Somewhat arbitrary, may need to be adjusted in future. +const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200); +const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20); + +void RecordProductEvents(bool first_run, + bool is_google_default_search, + bool is_google_homepage, + bool is_google_in_startpages, + bool already_ran, + bool omnibox_used, + bool homepage_used, + bool app_list_used) { + TRACE_EVENT0("RLZ", "RecordProductEvents"); + // Record the installation of chrome. We call this all the time but the rlz + // lib should ignore all but the first one. + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeOmnibox(), + rlz_lib::INSTALL); +#if !defined(OS_IOS) + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeHomePage(), + rlz_lib::INSTALL); + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeAppList(), + rlz_lib::INSTALL); +#endif // !defined(OS_IOS) + + if (!already_ran) { + // Do the initial event recording if is the first run or if we have an + // empty rlz which means we haven't got a chance to do it. + char omnibox_rlz[rlz_lib::kMaxRlzLength + 1]; + if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), omnibox_rlz, + rlz_lib::kMaxRlzLength)) { + omnibox_rlz[0] = 0; + } + + // Record if google is the initial search provider and/or home page. + if ((first_run || omnibox_rlz[0] == 0) && is_google_default_search) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeOmnibox(), + rlz_lib::SET_TO_GOOGLE); + } + +#if !defined(OS_IOS) + char homepage_rlz[rlz_lib::kMaxRlzLength + 1]; + if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeHomePage(), homepage_rlz, + rlz_lib::kMaxRlzLength)) { + homepage_rlz[0] = 0; + } + + if ((first_run || homepage_rlz[0] == 0) && + (is_google_homepage || is_google_in_startpages)) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeHomePage(), + rlz_lib::SET_TO_GOOGLE); + } + + char app_list_rlz[rlz_lib::kMaxRlzLength + 1]; + if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeAppList(), app_list_rlz, + rlz_lib::kMaxRlzLength)) { + app_list_rlz[0] = 0; + } + + // Record if google is the initial search provider and/or home page. + if ((first_run || app_list_rlz[0] == 0) && is_google_default_search) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeAppList(), + rlz_lib::SET_TO_GOOGLE); + } +#endif // !defined(OS_IOS) + } + + // Record first user interaction with the omnibox. We call this all the + // time but the rlz lib should ingore all but the first one. + if (omnibox_used) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeOmnibox(), + rlz_lib::FIRST_SEARCH); + } + +#if !defined(OS_IOS) + // Record first user interaction with the home page. We call this all the + // time but the rlz lib should ingore all but the first one. + if (homepage_used || is_google_in_startpages) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeHomePage(), + rlz_lib::FIRST_SEARCH); + } + + // Record first user interaction with the app list. We call this all the + // time but the rlz lib should ingore all but the first one. + if (app_list_used) { + rlz_lib::RecordProductEvent(rlz_lib::CHROME, + RLZTracker::ChromeAppList(), + rlz_lib::FIRST_SEARCH); + } +#endif // !defined(OS_IOS) +} + +bool SendFinancialPing(const std::string& brand, + const base::string16& lang, + const base::string16& referral) { + rlz_lib::AccessPoint points[] = {RLZTracker::ChromeOmnibox(), +#if !defined(OS_IOS) + RLZTracker::ChromeHomePage(), + RLZTracker::ChromeAppList(), +#endif + rlz_lib::NO_ACCESS_POINT}; + std::string lang_ascii(base::UTF16ToASCII(lang)); + std::string referral_ascii(base::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 + +RLZTracker* RLZTracker::tracker_ = nullptr; + +// static +RLZTracker* RLZTracker::GetInstance() { + return tracker_ ? tracker_ : Singleton<RLZTracker>::get(); +} + +RLZTracker::RLZTracker() + : first_run_(false), + send_ping_immediately_(false), + is_google_default_search_(false), + is_google_homepage_(false), + is_google_in_startpages_(false), + already_ran_(false), + omnibox_used_(false), + homepage_used_(false), + app_list_used_(false), + min_init_delay_(kMinInitDelay) { +} + +RLZTracker::~RLZTracker() { +} + +// static +void RLZTracker::SetRlzDelegate(scoped_ptr<RLZTrackerDelegate> delegate) { + GetInstance()->SetDelegate(delegate.Pass()); +} + +void RLZTracker::SetDelegate(scoped_ptr<RLZTrackerDelegate> delegate) { + DCHECK(delegate); + if (!delegate_) { + delegate_ = delegate.Pass(); + worker_pool_token_ = delegate_->GetBlockingPool()->GetSequenceToken(); + } +} + +// static +bool RLZTracker::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) { + return GetInstance()->Init(first_run, send_ping_immediately, delay, + is_google_default_search, is_google_homepage, + is_google_in_startpages); +} + +bool RLZTracker::Init(bool first_run, + bool send_ping_immediately, + base::TimeDelta delay, + bool is_google_default_search, + bool is_google_homepage, + bool is_google_in_startpages) { + first_run_ = first_run; + is_google_default_search_ = is_google_default_search; + is_google_homepage_ = is_google_homepage; + is_google_in_startpages_ = is_google_in_startpages; + send_ping_immediately_ = send_ping_immediately; + + // Enable zero delays for testing. + if (delegate_->ShouldEnableZeroDelayForTesting()) + EnableZeroDelayForTesting(); + + delay = std::min(kMaxInitDelay, std::max(min_init_delay_, delay)); + + if (delegate_->GetBrand(&brand_) && !delegate_->IsBrandOrganic(brand_)) { + // Register for notifications from the omnibox so that we can record when + // the user performs a first search. + delegate_->SetOmniboxSearchCallback( + base::Bind(&RLZTracker::RecordFirstSearch, base::Unretained(this), + ChromeOmnibox())); + +#if !defined(OS_IOS) + // Register for notifications from navigations, to see if the user has used + // the home page. + delegate_->SetHomepageSearchCallback( + base::Bind(&RLZTracker::RecordFirstSearch, base::Unretained(this), + ChromeHomePage())); +#endif + } + delegate_->GetReactivationBrand(&reactivation_brand_); + + // Could be null; don't run if so. RLZ will try again next restart. + net::URLRequestContextGetter* context_getter = delegate_->GetRequestContext(); + if (context_getter) { + rlz_lib::SetURLRequestContext(context_getter); + ScheduleDelayedInit(delay); + } + +#if !defined(OS_IOS) + // Prime the RLZ cache for the home page access point so that its avaiable + // for the startup page if needed (i.e., when the startup page is set to + // the home page). + GetAccessPointRlz(ChromeHomePage(), nullptr); +#endif // !defined(OS_IOS) + + return true; +} + +void RLZTracker::Cleanup() { + rlz_cache_.clear(); + if (delegate_) + delegate_->Cleanup(); +} + +void RLZTracker::ScheduleDelayedInit(base::TimeDelta delay) { + // The RLZTracker is a singleton object that outlives any runnable tasks + // that will be queued up. + delegate_->GetBlockingPool()->PostDelayedSequencedWorkerTask( + worker_pool_token_, FROM_HERE, + base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)), delay); +} + +void RLZTracker::DelayedInit() { + bool schedule_ping = false; + + // For organic brandcodes do not use rlz at all. Empty brandcode usually + // means a chromium install. This is ok. + if (!delegate_->IsBrandOrganic(brand_)) { + RecordProductEvents(first_run_, is_google_default_search_, + is_google_homepage_, is_google_in_startpages_, + already_ran_, omnibox_used_, homepage_used_, + app_list_used_); + schedule_ping = true; + } + + // If chrome has been reactivated, record the events for this brand + // as well. + if (!delegate_->IsBrandOrganic(reactivation_brand_)) { + rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str()); + RecordProductEvents(first_run_, is_google_default_search_, + is_google_homepage_, is_google_in_startpages_, + already_ran_, omnibox_used_, homepage_used_, + app_list_used_); + schedule_ping = true; + } + + already_ran_ = true; + + if (schedule_ping) + ScheduleFinancialPing(); +} + +void RLZTracker::ScheduleFinancialPing() { + delegate_->GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( + worker_pool_token_, FROM_HERE, + base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); +} + +void RLZTracker::PingNowImpl() { + TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl"); + base::string16 lang; + delegate_->GetLanguage(&lang); + if (lang.empty()) + lang = base::ASCIIToUTF16("en"); + base::string16 referral; + delegate_->GetReferral(&referral); + + if (!delegate_->IsBrandOrganic(brand_) && + SendFinancialPing(brand_, lang, referral)) { + delegate_->ClearReferral(); + + { + base::AutoLock lock(cache_lock_); + rlz_cache_.clear(); + } + + // Prime the RLZ cache for the access points we are interested in. + GetAccessPointRlz(RLZTracker::ChromeOmnibox(), nullptr); +#if !defined(OS_IOS) + GetAccessPointRlz(RLZTracker::ChromeHomePage(), nullptr); + GetAccessPointRlz(RLZTracker::ChromeAppList(), nullptr); +#endif // !defined(OS_IOS) + } + + if (!delegate_->IsBrandOrganic(reactivation_brand_)) { + rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str()); + SendFinancialPing(reactivation_brand_, lang, referral); + } +} + +bool RLZTracker::SendFinancialPing(const std::string& brand, + const base::string16& lang, + const base::string16& referral) { + return ::rlz::SendFinancialPing(brand, lang, referral); +} + +// static +bool RLZTracker::RecordProductEvent(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id) { + return GetInstance()->RecordProductEventImpl(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. + if (!reactivation_brand_.empty()) { + 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, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id) { + if (!delegate_->IsOnUIThread()) + return false; + + delegate_->GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( + worker_pool_token_, FROM_HERE, + base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent), 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; + + bool* record_used = GetAccessPointRecord(point); + + // 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)) + *record_used = true; + else if (send_ping_immediately_ && point == ChromeOmnibox()) + ScheduleDelayedInit(base::TimeDelta()); +} + +bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) { + if (!delegate_->IsOnUIThread()) + return false; + delegate_->GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( + worker_pool_token_, FROM_HERE, + base::Bind(&RLZTracker::RecordFirstSearch, base::Unretained(this), point), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + return true; +} + +bool* RLZTracker::GetAccessPointRecord(rlz_lib::AccessPoint point) { + if (point == ChromeOmnibox()) + return &omnibox_used_; +#if !defined(OS_IOS) + if (point == ChromeHomePage()) + return &homepage_used_; + if (point == ChromeAppList()) + return &app_list_used_; +#endif // !defined(OS_IOS) + NOTREACHED(); + return nullptr; +} + +// static +std::string RLZTracker::GetAccessPointHttpHeader(rlz_lib::AccessPoint point) { + TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointHttpHeader"); + std::string extra_headers; + base::string16 rlz_string; + RLZTracker::GetAccessPointRlz(point, &rlz_string); + if (!rlz_string.empty()) { + net::HttpUtil::AppendHeaderIfMissing("X-Rlz-String", + base::UTF16ToUTF8(rlz_string), + &extra_headers); + } + + 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::GetAccessPointRlz(rlz_lib::AccessPoint point, + base::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, + base::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; + } + } + + // 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; + + char str_rlz[rlz_lib::kMaxRlzLength + 1]; + if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength)) + return false; + + base::string16 rlz_local(base::ASCIIToUTF16(str_rlz)); + if (rlz) + *rlz = rlz_local; + + base::AutoLock lock(cache_lock_); + rlz_cache_[point] = rlz_local; + return true; +} + +bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) { + if (!delegate_->IsOnUIThread()) + return false; + + base::string16* not_used = nullptr; + delegate_->GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( + worker_pool_token_, FROM_HERE, + base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point, + not_used), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + return true; +} + +#if defined(OS_CHROMEOS) +// static +void RLZTracker::ClearRlzState() { + GetInstance()->ClearRlzStateImpl(); +} + +void RLZTracker::ClearRlzStateImpl() { + if (ScheduleClearRlzState()) + return; + rlz_lib::ClearAllProductEvents(rlz_lib::CHROME); +} + +bool RLZTracker::ScheduleClearRlzState() { + if (!delegate_->IsOnUIThread()) + return false; + + delegate_->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()->Cleanup(); + rlz_lib::SetURLRequestContext(nullptr); +} + +// static +void RLZTracker::EnableZeroDelayForTesting() { + GetInstance()->min_init_delay_ = base::TimeDelta(); +} + +#if !defined(OS_IOS) +// static +void RLZTracker::RecordAppListSearch() { + GetInstance()->RecordFirstSearch(RLZTracker::ChromeAppList()); +} +#endif + +} // namespace rlz diff --git a/components/rlz/rlz_tracker.h b/components/rlz/rlz_tracker.h new file mode 100644 index 0000000..1236aa2 --- /dev/null +++ b/components/rlz/rlz_tracker.h @@ -0,0 +1,242 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_RLZ_RLZ_TRACKER_H_ +#define COMPONENTS_RLZ_RLZ_TRACKER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/strings/string16.h" +#include "base/threading/sequenced_worker_pool.h" +#include "base/time/time.h" +#include "rlz/lib/rlz_lib.h" + +namespace net { +class URLRequestContextGetter; +} + +namespace rlz { + +class RLZTrackerDelegate; + +// 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 +// not contain information that can be used to identify a user or to infer +// browsing habits. The API in this file is a wrapper around the open source +// RLZ library which can be found at http://code.google.com/p/rlz. +// +// For partner or bundled installs, the RLZ might send more information +// according to the terms disclosed in the EULA. + +class RLZTracker { + public: + // Sets the RLZTrackerDelegate that should be used by the global RLZTracker + // instance. Must be called before calling any other method of RLZTracker. + static void SetRlzDelegate(scoped_ptr<RLZTrackerDelegate> delegate); + + // 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 + // true. + // + // When |send_ping_immediately| is true, a financial ping should be sent + // immediately after a first search is recorded, without waiting for |delay|. + // However, we only want this behaviour on first run. + // + // If the chrome brand is organic (no partners) then the pings don't occur. + static 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); + + // 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, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id); + + // For the point parameter of RecordProductEvent. + static rlz_lib::AccessPoint ChromeOmnibox(); +#if !defined(OS_IOS) + static rlz_lib::AccessPoint ChromeHomePage(); + static rlz_lib::AccessPoint ChromeAppList(); +#endif + + // Gets the HTTP header value that can be added to requests from the + // specific access point. The string returned is of the form: + // + // "X-Rlz-String: <access-point-rlz>\r\n" + // + static std::string GetAccessPointHttpHeader(rlz_lib::AccessPoint point); + + // Gets the RLZ value of the access point. + // Returns false if the rlz string could not be obtained. In some cases + // an empty string can be returned which is not an error. + static bool GetAccessPointRlz(rlz_lib::AccessPoint point, + base::string16* rlz); + + // Invoked during shutdown to clean up any state created by RLZTracker. + static void CleanupRlz(); + +#if defined(OS_CHROMEOS) + // Clears all product state. Should be called when turning RLZ off. On other + // platforms, this is done by product uninstaller. + static void ClearRlzState(); +#endif + + // This method is public for use by the Singleton class. + static RLZTracker* GetInstance(); + + // Enables zero delay for InitRlzDelayed. For testing only. + static void EnableZeroDelayForTesting(); + +#if !defined(OS_IOS) + // Records that the app list search has been used. + static void RecordAppListSearch(); +#endif + + // 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(); + + // Performs initialization of RLZ tracker that is purposefully delayed so + // that it does not interfere with chrome startup time. + virtual void DelayedInit(); + + // Used by test code to override the default RLZTracker instance returned + // by GetInstance(). + void set_tracker(RLZTracker* tracker) { tracker_ = tracker; } + + // 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>; + + // Implementation called from SetRlzDelegate() static method. + void SetDelegate(scoped_ptr<RLZTrackerDelegate> delegate); + + // Implementation called from InitRlzDelayed() static method. + bool Init(bool first_run, + bool send_ping_immediately, + base::TimeDelta delay, + bool is_google_default_search, + bool is_google_homepage, + bool is_google_in_startpages); + + // Implementation called from CleanupRlz static method. + void Cleanup(); + + // 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. Passed as bound callback to RLZTrackerDelegate. + void RecordFirstSearch(rlz_lib::AccessPoint point); + + // Implementation called from GetAccessPointRlz() static method. + bool GetAccessPointRlzImpl(rlz_lib::AccessPoint point, base::string16* rlz); + + // Schedules the delayed initialization. This method is virtual to allow + // tests to override how the scheduling is done. + virtual 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); + + // 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); + + // Schedules a call to rlz_lib::SendFinancialPing(). This method is virtual + // to allow tests to override how the scheduling is done. + virtual void ScheduleFinancialPing(); + + // 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); + + // 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 base::string16& lang, + const base::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(); +#endif + + // Returns a pointer to the bool corresponding to whether |point| has been + // used but not reported. + bool* GetAccessPointRecord(rlz_lib::AccessPoint point); + + // 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_; + + // Delegate abstracting embedder specific knowledge. Must not be null. + scoped_ptr<RLZTrackerDelegate> delegate_; + + // Configuation data for RLZ tracker. Set by call to Init(). + bool first_run_; + bool send_ping_immediately_; + bool is_google_default_search_; + bool is_google_homepage_; + bool is_google_in_startpages_; + + // Unique sequence token so that tasks posted by RLZTracker are executed + // sequentially in the blocking pool. + base::SequencedWorkerPool::SequenceToken worker_pool_token_; + + // Keeps track if the RLZ tracker has already performed its delayed + // 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. + base::Lock cache_lock_; + std::map<rlz_lib::AccessPoint, base::string16> rlz_cache_; + + // Keeps track of whether the omnibox, home page or app list have been used. + bool omnibox_used_; + bool homepage_used_; + bool app_list_used_; + + // Main and (optionally) reactivation brand codes, assigned on UI thread. + std::string brand_; + std::string reactivation_brand_; + + // Minimum delay before sending financial ping after initialization. + base::TimeDelta min_init_delay_; + + DISALLOW_COPY_AND_ASSIGN(RLZTracker); +}; + +} // namespace rlz + +#endif // COMPONENTS_RLZ_RLZ_TRACKER_H_ diff --git a/components/rlz/rlz_tracker_chromeos.cc b/components/rlz/rlz_tracker_chromeos.cc new file mode 100644 index 0000000..b63c934 --- /dev/null +++ b/components/rlz/rlz_tracker_chromeos.cc @@ -0,0 +1,24 @@ +// Copyright 2014 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 "components/rlz/rlz_tracker.h" + +namespace rlz { + +// static +rlz_lib::AccessPoint RLZTracker::ChromeOmnibox() { + return rlz_lib::CHROMEOS_OMNIBOX; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeHomePage() { + return rlz_lib::CHROMEOS_HOME_PAGE; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeAppList() { + return rlz_lib::CHROMEOS_APP_LIST; +} + +} // namespace rlz diff --git a/components/rlz/rlz_tracker_delegate.cc b/components/rlz/rlz_tracker_delegate.cc new file mode 100644 index 0000000..84f35aa --- /dev/null +++ b/components/rlz/rlz_tracker_delegate.cc @@ -0,0 +1,15 @@ +// Copyright 2015 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 "components/rlz/rlz_tracker_delegate.h" + +namespace rlz { + +RLZTrackerDelegate::RLZTrackerDelegate() { +} + +RLZTrackerDelegate::~RLZTrackerDelegate() { +} + +} // namespace rlz diff --git a/components/rlz/rlz_tracker_delegate.h b/components/rlz/rlz_tracker_delegate.h new file mode 100644 index 0000000..d1270e4 --- /dev/null +++ b/components/rlz/rlz_tracker_delegate.h @@ -0,0 +1,86 @@ +// Copyright 2015 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. + +#ifndef COMPONENTS_RLZ_RLZ_TRACKER_DELEGATE_H_ +#define COMPONENTS_RLZ_RLZ_TRACKER_DELEGATE_H_ + +#include <string> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "base/threading/sequenced_worker_pool.h" + +namespace base { +class SequencedWorkerPool; +} + +namespace net { +class URLRequestContextGetter; +} + +namespace rlz { + +// RLZTrackerDelegate is an abstract interface that provides access to embedder +// specific singletons or gives information about the embedder environment. +class RLZTrackerDelegate { + public: + RLZTrackerDelegate() {} + virtual ~RLZTrackerDelegate() {} + + // Invoked during RLZTracker cleanup, to request the cleanup of the delegate. + virtual void Cleanup() = 0; + + // Returns whether the current thread is the UI thread. + virtual bool IsOnUIThread() = 0; + + // Returns the SequencedWorkerPool where the RLZTracker will post its tasks + // that should be executed in the background. + virtual base::SequencedWorkerPool* GetBlockingPool() = 0; + + // Returns the URLRequestContextGetter to use for network connections. + virtual net::URLRequestContextGetter* GetRequestContext() = 0; + + // Returns the brand code for the installation of Chrome in |brand| and a + // boolean indicating whether the operation was a success or not. + virtual bool GetBrand(std::string* brand) = 0; + + // Returns whether |brand| is an organic brand. + virtual bool IsBrandOrganic(const std::string& brand) = 0; + + // Returns the reactivation brand code for Chrome in |brand| and a boolean + // indicating whether the operation was a success or not. + virtual bool GetReactivationBrand(std::string* brand) = 0; + + // Returns true if RLZTracker should ignore initial delay for testing. + virtual bool ShouldEnableZeroDelayForTesting() = 0; + + // Returns the installation language in |language| and a boolean indicating + // whether the operation was a success or not. + virtual bool GetLanguage(base::string16* language) = 0; + + // Returns the referral code in |referral| and a boolean indicating whether + // the operation was a success or not. Deprecated. + virtual bool GetReferral(base::string16* referral) = 0; + + // Clears the referral code. Deprecated. + virtual bool ClearReferral() = 0; + + // Registers |callback| to be invoked the next time the user perform a search + // using Google search engine via the omnibox. Callback will invoked at most + // once. + virtual void SetOmniboxSearchCallback(const base::Closure& callback) = 0; + + // Registers |callback| to be invoked the next time the user perform a search + // using Google search engine via the homepage. Callback will invoked at most + // once. + virtual void SetHomepageSearchCallback(const base::Closure& callback) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RLZTrackerDelegate); +}; + +} // namespace rlz + +#endif // COMPONENTS_RLZ_RLZ_TRACKER_DELEGATE_H_ diff --git a/components/rlz/rlz_tracker_ios.cc b/components/rlz/rlz_tracker_ios.cc new file mode 100644 index 0000000..e2b110c --- /dev/null +++ b/components/rlz/rlz_tracker_ios.cc @@ -0,0 +1,19 @@ +// Copyright 2014 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 "components/rlz/rlz_tracker.h" + +#include "rlz/lib/rlz_lib.h" +#include "ui/base/device_form_factor.h" + +namespace rlz { + +// static +rlz_lib::AccessPoint RLZTracker::ChromeOmnibox() { + return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE + ? rlz_lib::CHROME_IOS_OMNIBOX_MOBILE + : rlz_lib::CHROME_IOS_OMNIBOX_TABLET; +} + +} // namespace rlz diff --git a/components/rlz/rlz_tracker_mac.cc b/components/rlz/rlz_tracker_mac.cc new file mode 100644 index 0000000..186f9e6 --- /dev/null +++ b/components/rlz/rlz_tracker_mac.cc @@ -0,0 +1,24 @@ +// Copyright 2014 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 "components/rlz/rlz_tracker.h" + +namespace rlz { + +// static +rlz_lib::AccessPoint RLZTracker::ChromeOmnibox() { + return rlz_lib::CHROME_MAC_OMNIBOX; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeHomePage() { + return rlz_lib::CHROME_MAC_HOME_PAGE; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeAppList() { + return rlz_lib::CHROME_MAC_APP_LIST; +} + +} // namespace rlz diff --git a/components/rlz/rlz_tracker_unittest.cc b/components/rlz/rlz_tracker_unittest.cc new file mode 100644 index 0000000..eb33d89 --- /dev/null +++ b/components/rlz/rlz_tracker_unittest.cc @@ -0,0 +1,1009 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/rlz/rlz_tracker.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/thread_task_runner_handle.h" +#include "base/threading/sequenced_worker_pool.h" +#include "base/time/time.h" +#include "components/rlz/rlz_tracker_delegate.h" +#include "net/url_request/url_request_test_util.h" +#include "rlz/test/rlz_test_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_IOS) +#include "ui/base/device_form_factor.h" +#endif + +using testing::AssertionResult; +using testing::AssertionSuccess; +using testing::AssertionFailure; + +namespace rlz { +namespace { + +class TestRLZTrackerDelegate : public RLZTrackerDelegate { + public: + TestRLZTrackerDelegate() + : worker_pool_(new base::SequencedWorkerPool(1, "TestRLZTracker")), + request_context_getter_(new net::TestURLRequestContextGetter( + base::ThreadTaskRunnerHandle::Get())) {} + + ~TestRLZTrackerDelegate() override { worker_pool_->Shutdown(); } + + void set_brand(const char* brand) { brand_override_ = brand; } + + void set_reactivation_brand(const char* reactivation_brand) { + // TODO(thakis): Reactivation doesn't exist on Mac yet. + reactivation_brand_override_ = reactivation_brand; + } + + void SimulateOmniboxUsage() { + using std::swap; + base::Closure callback; + swap(callback, on_omnibox_search_callback_); + if (!callback.is_null()) + callback.Run(); + } + + void SimulateHomepageUsage() { + using std::swap; + base::Closure callback; + swap(callback, on_homepage_search_callback_); + if (!callback.is_null()) + callback.Run(); + } + + // RLZTrackerDelegate implementation. + void Cleanup() override { + on_omnibox_search_callback_.Reset(); + on_homepage_search_callback_.Reset(); + } + + bool IsOnUIThread() override { return true; } + + base::SequencedWorkerPool* GetBlockingPool() override { + return worker_pool_.get(); + } + + net::URLRequestContextGetter* GetRequestContext() override { + return request_context_getter_.get(); + } + + bool GetBrand(std::string* brand) override { + *brand = brand_override_; + return true; + } + + bool IsBrandOrganic(const std::string& brand) override { + return brand.empty() || brand == "GGLS" || brand == "GGRS"; + } + + bool GetReactivationBrand(std::string* brand) override { + *brand = reactivation_brand_override_; + return true; + } + + bool ShouldEnableZeroDelayForTesting() override { return true; } + + bool GetLanguage(base::string16* language) override { return true; } + + bool GetReferral(base::string16* referral) override { return true; } + + bool ClearReferral() override { return true; } + + void SetOmniboxSearchCallback(const base::Closure& callback) override { + DCHECK(!callback.is_null()); + on_omnibox_search_callback_ = callback; + } + + void SetHomepageSearchCallback(const base::Closure& callback) override { + DCHECK(!callback.is_null()); + on_homepage_search_callback_ = callback; + } + + private: + scoped_refptr<base::SequencedWorkerPool> worker_pool_; + scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + + std::string brand_override_; + std::string reactivation_brand_override_; + base::Closure on_omnibox_search_callback_; + base::Closure on_homepage_search_callback_; + + DISALLOW_COPY_AND_ASSIGN(TestRLZTrackerDelegate); +}; + +// Dummy RLZ string for the access points. +const char kOmniboxRlzString[] = "test_omnibox"; +const char kNewOmniboxRlzString[] = "new_omnibox"; +#if !defined(OS_IOS) +const char kHomepageRlzString[] = "test_homepage"; +const char kNewHomepageRlzString[] = "new_homepage"; +const char kAppListRlzString[] = "test_applist"; +const char kNewAppListRlzString[] = "new_applist"; +#endif // !defined(OS_IOS) + +// Some helper macros to test it a string contains/does not contain a substring. + +AssertionResult CmpHelperSTRC(const char* str_expression, + const char* substr_expression, + const char* str, + const char* substr) { + if (nullptr != strstr(str, substr)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << substr_expression << ") in (" + << str_expression << "), actual: '" + << substr << "' not in '" << str << "'"; +} + +AssertionResult CmpHelperSTRNC(const char* str_expression, + const char* substr_expression, + const char* str, + const char* substr) { + if (nullptr == strstr(str, substr)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << substr_expression + << ") not in (" << str_expression << "), actual: '" + << substr << "' in '" << str << "'"; +} + +#define EXPECT_STR_CONTAINS(str, substr) \ + EXPECT_PRED_FORMAT2(CmpHelperSTRC, str, substr) + +#define EXPECT_STR_NOT_CONTAIN(str, substr) \ + EXPECT_PRED_FORMAT2(CmpHelperSTRNC, str, substr) + +} // namespace + +// Test class for RLZ tracker. Makes some member functions public and +// overrides others to make it easier to test. +class TestRLZTracker : public RLZTracker { + public: + using RLZTracker::InitRlzDelayed; + using RLZTracker::DelayedInit; + + TestRLZTracker() : assume_not_ui_thread_(true) { set_tracker(this); } + + ~TestRLZTracker() override { set_tracker(nullptr); } + + 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: + 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(); + } + + void ScheduleFinancialPing() override { PingNowImpl(); } + + bool ScheduleRecordProductEvent(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id) override { + return !assume_not_ui_thread_; + } + + bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) override { + return !assume_not_ui_thread_; + } + + bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) override { + return !assume_not_ui_thread_; + } + +#if defined(OS_CHROMEOS) + bool ScheduleClearRlzState() override { return !assume_not_ui_thread_; } +#endif + + bool SendFinancialPing(const std::string& brand, + const base::string16& lang, + const base::string16& referral) override { + // Don't ping the server during tests, just pretend as if we did. + EXPECT_FALSE(brand.empty()); + pinged_brands_.insert(brand); + + // Set new access points RLZ string, like the actual server ping would have + // done. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), + kNewOmniboxRlzString); +#if !defined(OS_IOS) + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeHomePage(), + kNewHomepageRlzString); + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeAppList(), + kNewAppListRlzString); +#endif // !defined(OS_IOS) + return true; + } + + std::set<std::string> pinged_brands_; + bool assume_not_ui_thread_; + + DISALLOW_COPY_AND_ASSIGN(TestRLZTracker); +}; + +class RlzLibTest : public testing::Test { + protected: + void SetUp() override; + void TearDown() override; + + void SetMainBrand(const char* brand); + void SetReactivationBrand(const char* brand); + + void SimulateOmniboxUsage(); + void SimulateHomepageUsage(); + void SimulateAppListUsage(); + void InvokeDelayedInit(); + + void ExpectEventRecorded(const char* event_name, bool expected); + void ExpectRlzPingSent(bool expected); + void ExpectReactivationRlzPingSent(bool expected); + + base::MessageLoop message_loop_; + TestRLZTrackerDelegate* delegate_; + scoped_ptr<TestRLZTracker> tracker_; + RlzLibTestNoMachineStateHelper m_rlz_test_helper_; +}; + +void RlzLibTest::SetUp() { + testing::Test::SetUp(); + m_rlz_test_helper_.SetUp(); + + delegate_ = new TestRLZTrackerDelegate; + tracker_.reset(new TestRLZTracker()); + RLZTracker::SetRlzDelegate(make_scoped_ptr(delegate_)); + + // Make sure a non-organic brand code is set in the registry or the RLZTracker + // is pretty much a no-op. + SetMainBrand("TEST"); + SetReactivationBrand(""); +} + +void RlzLibTest::TearDown() { + delegate_ = nullptr; + tracker_.reset(); + testing::Test::TearDown(); + m_rlz_test_helper_.TearDown(); +} + +void RlzLibTest::SetMainBrand(const char* brand) { + delegate_->set_brand(brand); +} + +void RlzLibTest::SetReactivationBrand(const char* brand) { + delegate_->set_reactivation_brand(brand); +} + +void RlzLibTest::SimulateOmniboxUsage() { + delegate_->SimulateOmniboxUsage(); +} + +void RlzLibTest::SimulateHomepageUsage() { + delegate_->SimulateHomepageUsage(); +} + +void RlzLibTest::SimulateAppListUsage() { +#if !defined(OS_IOS) + RLZTracker::RecordAppListSearch(); +#endif // !defined(OS_IOS) +} + +void RlzLibTest::InvokeDelayedInit() { + tracker_->DelayedInit(); +} + +void RlzLibTest::ExpectEventRecorded(const char* event_name, bool expected) { + char cgi[rlz_lib::kMaxCgiLength]; + GetProductEventsAsCgi(rlz_lib::CHROME, cgi, arraysize(cgi)); + if (expected) { + EXPECT_STR_CONTAINS(cgi, event_name); + } else { + EXPECT_STR_NOT_CONTAIN(cgi, event_name); + } +} + +void RlzLibTest::ExpectRlzPingSent(bool expected) { + std::string brand; + delegate_->GetBrand(&brand); + EXPECT_EQ(expected, tracker_->was_ping_sent_for_brand(brand.c_str())); +} + +void RlzLibTest::ExpectReactivationRlzPingSent(bool expected) { + std::string brand; + delegate_->GetReactivationBrand(&brand); + EXPECT_EQ(expected, tracker_->was_ping_sent_for_brand(brand.c_str())); +} + +// The events that affect the different RLZ scenarios are the following: +// +// A: the user starts chrome for the first time +// B: the user stops chrome +// C: the user start a subsequent time +// D: the user stops chrome again +// I: the RLZTracker::DelayedInit() method is invoked +// X: the user performs a search using the omnibox +// Y: the user performs a search using the home page +// Z: the user performs a search using the app list +// +// The events A to D happen in chronological order, but the other events +// may happen at any point between A-B or C-D, in no particular order. +// +// The visible results of the scenarios on Win are: +// +// C1I event is recorded +// C2I event is recorded +// C7I event is recorded +// C1F event is recorded +// C2F event is recorded +// C7F event is recorded +// C1S event is recorded +// C2S event is recorded +// C7S event is recorded +// RLZ ping sent +// +// On Mac, C5 / C6 / C8 are sent instead of C1 / C2 / C7. +// On ChromeOS, CA / CB / CC are sent, respectively. +// +// On iOS, only the omnibox events are recorded, and the value send depends +// on the device form factor (phone or tablet). +// +// Variations on the above scenarios: +// +// - if the delay specified to InitRlzDelayed() is negative, then the RLZ +// ping should be sent out at the time of event X and not wait for I +// +// Also want to test that pre-warming the RLZ string cache works correctly. + +#if defined(OS_WIN) +const char kOmniboxInstall[] = "C1I"; +const char kOmniboxSetToGoogle[] = "C1S"; +const char kOmniboxFirstSearch[] = "C1F"; + +const char kHomepageInstall[] = "C2I"; +const char kHomepageSetToGoogle[] = "C2S"; +const char kHomepageFirstSearch[] = "C2F"; + +const char kAppListInstall[] = "C7I"; +const char kAppListSetToGoogle[] = "C7S"; +const char kAppListFirstSearch[] = "C7F"; +#elif defined(OS_IOS) +const char kOmniboxInstallPhone[] = "CDI"; +const char kOmniboxSetToGooglePhone[] = "CDS"; +const char kOmniboxFirstSearchPhone[] = "CDF"; + +const char kOmniboxInstallTablet[] = "C9I"; +const char kOmniboxSetToGoogleTablet[] = "C9S"; +const char kOmniboxFirstSearchTablet[] = "C9F"; +#elif defined(OS_MACOSX) +const char kOmniboxInstall[] = "C5I"; +const char kOmniboxSetToGoogle[] = "C5S"; +const char kOmniboxFirstSearch[] = "C5F"; + +const char kHomepageInstall[] = "C6I"; +const char kHomepageSetToGoogle[] = "C6S"; +const char kHomepageFirstSearch[] = "C6F"; + +const char kAppListInstall[] = "C8I"; +const char kAppListSetToGoogle[] = "C8S"; +const char kAppListFirstSearch[] = "C8F"; +#elif defined(OS_CHROMEOS) +const char kOmniboxInstall[] = "CAI"; +const char kOmniboxSetToGoogle[] = "CAS"; +const char kOmniboxFirstSearch[] = "CAF"; + +const char kHomepageInstall[] = "CBI"; +const char kHomepageSetToGoogle[] = "CBS"; +const char kHomepageFirstSearch[] = "CBF"; + +const char kAppListInstall[] = "CCI"; +const char kAppListSetToGoogle[] = "CCS"; +const char kAppListFirstSearch[] = "CCF"; +#endif + +const char* OmniboxInstall() { +#if defined(OS_IOS) + return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET + ? kOmniboxInstallTablet + : kOmniboxInstallPhone; +#else + return kOmniboxInstall; +#endif +} + +const char* OmniboxSetToGoogle() { +#if defined(OS_IOS) + return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET + ? kOmniboxSetToGoogleTablet + : kOmniboxSetToGooglePhone; +#else + return kOmniboxSetToGoogle; +#endif +} + +const char* OmniboxFirstSearch() { +#if defined(OS_IOS) + return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET + ? kOmniboxFirstSearchTablet + : kOmniboxFirstSearchPhone; +#else + return kOmniboxFirstSearch; +#endif +} + +const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(20); + +TEST_F(RlzLibTest, RecordProductEvent) { + RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::ChromeOmnibox(), + rlz_lib::FIRST_SEARCH); + + ExpectEventRecorded(OmniboxFirstSearch(), true); +} + +TEST_F(RlzLibTest, QuickStopAfterStart) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, true); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, DelayedInitOnly) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), true); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, true); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, DelayedInitOnlyGoogleAsStartup) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, true); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStrings) { + TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, false); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), true); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, true); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStringsGoogleAsStartup) { + TestRLZTracker::InitRlzDelayed(false, false, kDelay, false, false, true); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRun) { + // Set some dummy RLZ strings to simulate that we already ran before and + // performed a successful ping to the RLZ server. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), kOmniboxRlzString); +#if !defined(OS_IOS) + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeHomePage(), kHomepageRlzString); + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeAppList(), kAppListRlzString); +#endif // !defined(OS_IOS) + + TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, true); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, DelayedInitOnlyNoGoogleDefaultSearchOrHomepageOrStartup) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, false); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, OmniboxUsageOnly) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + SimulateOmniboxUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), true); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, HomepageUsageOnly) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + SimulateHomepageUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, AppListUsageOnly) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + SimulateAppListUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, true); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, UsageBeforeDelayedInit) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + SimulateOmniboxUsage(); + SimulateHomepageUsage(); + SimulateAppListUsage(); + InvokeDelayedInit(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), true); + ExpectEventRecorded(OmniboxFirstSearch(), true); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, true); + ExpectEventRecorded(kAppListFirstSearch, true); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, UsageAfterDelayedInit) { + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + SimulateOmniboxUsage(); + SimulateHomepageUsage(); + SimulateAppListUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), true); + ExpectEventRecorded(OmniboxFirstSearch(), true); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, true); + ExpectEventRecorded(kAppListFirstSearch, true); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, OmniboxUsageSendsPingWhenSendPingImmediately) { + TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false); + SimulateOmniboxUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), true); + ExpectEventRecorded(OmniboxSetToGoogle(), true); + ExpectEventRecorded(OmniboxFirstSearch(), true); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, true); + ExpectEventRecorded(kHomepageSetToGoogle, true); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, true); + ExpectEventRecorded(kAppListSetToGoogle, true); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(true); +} + +TEST_F(RlzLibTest, HomepageUsageDoesNotSendPingWhenSendPingImmediately) { + TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false); + SimulateHomepageUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, StartupUsageDoesNotSendPingWhenSendPingImmediately) { + TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, false, true); + SimulateHomepageUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, true); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, false); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, AppListUsageDoesNotSendPingWhenSendPingImmediately) { + TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, false, false); + SimulateAppListUsage(); + + // Omnibox events. + ExpectEventRecorded(OmniboxInstall(), false); + ExpectEventRecorded(OmniboxSetToGoogle(), false); + ExpectEventRecorded(OmniboxFirstSearch(), false); + +#if !defined(OS_IOS) + // Home page events. + ExpectEventRecorded(kHomepageInstall, false); + ExpectEventRecorded(kHomepageSetToGoogle, false); + ExpectEventRecorded(kHomepageFirstSearch, false); + + // App list events. + ExpectEventRecorded(kAppListInstall, false); + ExpectEventRecorded(kAppListSetToGoogle, false); + ExpectEventRecorded(kAppListFirstSearch, true); +#endif // !defined(OS_IOS) + + ExpectRlzPingSent(false); +} + +TEST_F(RlzLibTest, GetAccessPointRlzOnIoThread) { + // Set dummy RLZ string. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), kOmniboxRlzString); + + base::string16 rlz; + + tracker_->set_assume_not_ui_thread(true); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); +} + +TEST_F(RlzLibTest, GetAccessPointRlzNotOnIoThread) { + // Set dummy RLZ string. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), kOmniboxRlzString); + + base::string16 rlz; + + tracker_->set_assume_not_ui_thread(false); + EXPECT_FALSE( + RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); +} + +TEST_F(RlzLibTest, GetAccessPointRlzIsCached) { + // Set dummy RLZ string. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), kOmniboxRlzString); + + base::string16 rlz; + + tracker_->set_assume_not_ui_thread(false); + EXPECT_FALSE( + RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + + tracker_->set_assume_not_ui_thread(true); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); + + tracker_->set_assume_not_ui_thread(false); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); +} + +TEST_F(RlzLibTest, PingUpdatesRlzCache) { + // Set dummy RLZ string. + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeOmnibox(), kOmniboxRlzString); +#if !defined(OS_IOS) + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeHomePage(), kHomepageRlzString); + rlz_lib::SetAccessPointRlz(RLZTracker::ChromeAppList(), kAppListRlzString); +#endif // !defined(OS_IOS) + + base::string16 rlz; + + // Prime the cache. + tracker_->set_assume_not_ui_thread(true); + + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); +#if !defined(OS_IOS) + EXPECT_TRUE(RLZTracker::GetAccessPointRlz( + RLZTracker::ChromeHomePage(), &rlz)); + EXPECT_STREQ(kHomepageRlzString, base::UTF16ToUTF8(rlz).c_str()); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeAppList(), &rlz)); + EXPECT_STREQ(kAppListRlzString, base::UTF16ToUTF8(rlz).c_str()); +#endif // !defined(OS_IOS) + + // Make sure cache is valid. + tracker_->set_assume_not_ui_thread(false); + + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); +#if !defined(OS_IOS) + EXPECT_TRUE(RLZTracker::GetAccessPointRlz( + RLZTracker::ChromeHomePage(), &rlz)); + EXPECT_STREQ(kHomepageRlzString, base::UTF16ToUTF8(rlz).c_str()); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeAppList(), &rlz)); + EXPECT_STREQ(kAppListRlzString, base::UTF16ToUTF8(rlz).c_str()); +#endif // !defined(OS_IOS) + + // Perform ping. + tracker_->set_assume_not_ui_thread(true); + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + ExpectRlzPingSent(true); + + // Make sure cache is now updated. + tracker_->set_assume_not_ui_thread(false); + + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), &rlz)); + EXPECT_STREQ(kNewOmniboxRlzString, base::UTF16ToUTF8(rlz).c_str()); +#if !defined(OS_IOS) + EXPECT_TRUE(RLZTracker::GetAccessPointRlz( + RLZTracker::ChromeHomePage(), &rlz)); + EXPECT_STREQ(kNewHomepageRlzString, base::UTF16ToUTF8(rlz).c_str()); + EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::ChromeAppList(), &rlz)); + EXPECT_STREQ(kNewAppListRlzString, base::UTF16ToUTF8(rlz).c_str()); +#endif // !defined(OS_IOS) +} + +// TODO(thakis): Reactivation doesn't exist on Mac yet. +TEST_F(RlzLibTest, ReactivationNonOrganicNonOrganic) { + SetReactivationBrand("REAC"); + + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + + ExpectRlzPingSent(true); + ExpectReactivationRlzPingSent(true); +} + +TEST_F(RlzLibTest, ReactivationOrganicNonOrganic) { + SetMainBrand("GGLS"); + SetReactivationBrand("REAC"); + + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + + ExpectRlzPingSent(false); + ExpectReactivationRlzPingSent(true); +} + +TEST_F(RlzLibTest, ReactivationNonOrganicOrganic) { + SetMainBrand("TEST"); + SetReactivationBrand("GGLS"); + + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + + ExpectRlzPingSent(true); + ExpectReactivationRlzPingSent(false); +} + +TEST_F(RlzLibTest, ReactivationOrganicOrganic) { + SetMainBrand("GGLS"); + SetReactivationBrand("GGRS"); + + TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false); + InvokeDelayedInit(); + + ExpectRlzPingSent(false); + ExpectReactivationRlzPingSent(false); +} + +#if defined(OS_CHROMEOS) +TEST_F(RlzLibTest, ClearRlzState) { + RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::ChromeOmnibox(), + rlz_lib::FIRST_SEARCH); + + ExpectEventRecorded(OmniboxFirstSearch(), true); + + RLZTracker::ClearRlzState(); + + ExpectEventRecorded(OmniboxFirstSearch(), false); +} +#endif // defined(OS_CHROMEOS) + +} // namespace rlz diff --git a/components/rlz/rlz_tracker_win.cc b/components/rlz/rlz_tracker_win.cc new file mode 100644 index 0000000..0e2055c --- /dev/null +++ b/components/rlz/rlz_tracker_win.cc @@ -0,0 +1,24 @@ +// Copyright 2014 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 "components/rlz/rlz_tracker.h" + +namespace rlz { + +// static +rlz_lib::AccessPoint RLZTracker::ChromeOmnibox() { + return rlz_lib::CHROME_OMNIBOX; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeHomePage() { + return rlz_lib::CHROME_HOME_PAGE; +} + +// static +rlz_lib::AccessPoint RLZTracker::ChromeAppList() { + return rlz_lib::CHROME_APP_LIST; +} + +} // namespace rlz |
