summaryrefslogtreecommitdiffstats
path: root/chrome/browser/rlz/rlz_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/rlz/rlz_unittest.cc')
-rw-r--r--chrome/browser/rlz/rlz_unittest.cc547
1 files changed, 516 insertions, 31 deletions
diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc
index 6a5e85d..96816a4 100644
--- a/chrome/browser/rlz/rlz_unittest.cc
+++ b/chrome/browser/rlz/rlz_unittest.cc
@@ -4,48 +4,533 @@
#include "chrome/browser/rlz/rlz.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
#include "base/path_service.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/env_vars.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "content/browser/tab_contents/navigation_entry.h"
+#include "content/common/notification_details.h"
+#include "content/common/notification_service.h"
+#include "content/common/notification_source.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::win::RegKey;
+using registry_util::RegistryOverrideManager;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+using testing::AssertionFailure;
namespace {
-// Gets rid of registry leftovers from testing. Returns false if there
-// is nothing to clean.
-bool CleanValue(const wchar_t* key_name, const wchar_t* value) {
- RegKey key;
- if (key.Open(HKEY_CURRENT_USER, key_name, KEY_READ | KEY_WRITE) !=
- ERROR_SUCCESS)
- return false;
- EXPECT_EQ(ERROR_SUCCESS, key.DeleteValue(value));
- return true;
+// Registry path to overridden hive.
+const wchar_t kRlzTempHkcu[] = L"rlz_hkcu";
+const wchar_t kRlzTempHklm[] = L"rlz_hklm";
+
+// Dummy RLZ string for the access points.
+const char kOmniboxRlzString[] = "test_omnibox";
+const char kHomepageRlzString[] = "test_homepage";
+
+// 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 (NULL != strstr(str, substr)) {
+ return AssertionSuccess();
+ }
+
+ return AssertionFailure() << "Expected: (" << substr_expression << ") in ("
+ << str_expression << "), actual: '"
+ << substr << "' not in '" << str << "'";
}
-// The chrome events RLZ key lives here.
-const wchar_t kKeyName[] = L"Software\\Google\\Common\\Rlz\\Events\\C";
+AssertionResult CmpHelperSTRNC(const char* str_expression,
+ const char* substr_expression,
+ const char* str,
+ const char* substr) {
+ if (NULL == 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(RlzLibTest, RecordProductEvent) {
- DWORD recorded_value = 0;
- EXPECT_TRUE(RLZTracker::RecordProductEvent(rlz_lib::CHROME,
- rlz_lib::CHROME_OMNIBOX, rlz_lib::FIRST_SEARCH));
- const wchar_t kEvent1[] = L"C1F";
- RegKey key1;
- EXPECT_EQ(ERROR_SUCCESS, key1.Open(HKEY_CURRENT_USER, kKeyName, KEY_READ));
- EXPECT_EQ(ERROR_SUCCESS, key1.ReadValueDW(kEvent1, &recorded_value));
- EXPECT_EQ(1, recorded_value);
- EXPECT_TRUE(CleanValue(kKeyName, kEvent1));
-
- EXPECT_TRUE(RLZTracker::RecordProductEvent(rlz_lib::CHROME,
- rlz_lib::CHROME_HOME_PAGE, rlz_lib::SET_TO_GOOGLE));
- const wchar_t kEvent2[] = L"C2S";
- RegKey key2;
- EXPECT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, kKeyName, KEY_READ));
- DWORD value = 0;
- EXPECT_EQ(ERROR_SUCCESS, key2.ReadValueDW(kEvent2, &recorded_value));
- EXPECT_EQ(1, recorded_value);
- EXPECT_TRUE(CleanValue(kKeyName, kEvent2));
+// 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::DelayedInit;
+ using RLZTracker::Observe;
+ using RLZTracker::RLZ_PAGETRANSITION_HOME_PAGE;
+
+ TestRLZTracker() : pingnow_called_(false), assume_io_thread_(false) {
+ set_tracker(this);
+ }
+
+ virtual ~TestRLZTracker() {
+ set_tracker(NULL);
+ }
+
+ bool pingnow_called() const {
+ return pingnow_called_;
+ }
+
+ bool assume_io_thread() const {
+ return assume_io_thread_;
+ }
+
+ void set_assume_io_thread(bool assume_io_thread) {
+ assume_io_thread_ = assume_io_thread;
+ }
+
+ private:
+ virtual void ScheduleDelayedInit(int 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 == 0)
+ DelayedInit();
+ }
+
+ virtual void ScheduleFinancialPing() OVERRIDE {
+ PingNow(this);
+ }
+
+ virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) OVERRIDE {
+ return !assume_io_thread_;
+ }
+
+ virtual bool SendFinancialPing(const std::wstring& brand,
+ const std::wstring& lang,
+ const std::wstring& referral,
+ bool exclude_id) OVERRIDE {
+ // Don't ping the server during tests.
+ pingnow_called_ = true;
+ return true;
+ }
+
+ bool pingnow_called_;
+ bool assume_io_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestRLZTracker);
+};
+
+class RlzLibTest : public testing::Test {
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ void SimulateOmniboxUsage();
+ void SimulateHomepageUsage();
+ void InvokeDelayedInit();
+
+ void ExpectEventRecorded(const char* event_name, bool expected);
+ void ExpectRlzPingSent(bool expected);
+
+ TestRLZTracker tracker_;
+ RegistryOverrideManager override_manager_;
+};
+
+void RlzLibTest::SetUp() {
+ testing::Test::SetUp();
+
+ // Before overriding HKLM for the tests, we need to set it up correctly
+ // so that the rlz_lib calls work. This needs to be done before we do the
+ // override.
+
+ std::wstring temp_hklm_path = base::StringPrintf(
+ L"%ls\\%ls",
+ RegistryOverrideManager::kTempTestKeyPath,
+ kRlzTempHklm);
+
+ base::win::RegKey hklm;
+ ASSERT_EQ(ERROR_SUCCESS, hklm.Create(HKEY_CURRENT_USER,
+ temp_hklm_path.c_str(),
+ KEY_READ));
+
+ std::wstring temp_hkcu_path = base::StringPrintf(
+ L"%ls\\%ls",
+ RegistryOverrideManager::kTempTestKeyPath,
+ kRlzTempHkcu);
+
+ base::win::RegKey hkcu;
+ ASSERT_EQ(ERROR_SUCCESS, hkcu.Create(HKEY_CURRENT_USER,
+ temp_hkcu_path.c_str(),
+ KEY_READ));
+
+ rlz_lib::InitializeTempHivesForTesting(hklm, hkcu);
+
+ // Its important to override HKLM before HKCU because of the registry
+ // initialization performed above.
+ override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, kRlzTempHklm);
+ override_manager_.OverrideRegistry(HKEY_CURRENT_USER, kRlzTempHkcu);
+
+ // Make sure a non-organic brand code is set in the registry or the RLZTracker
+ // is pretty much a no-op.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ std::wstring reg_path = dist->GetStateKey();
+ RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_SET_VALUE);
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(google_update::kRegRLZBrandField,
+ L"TEST"));
+}
+
+void RlzLibTest::TearDown() {
+ testing::Test::TearDown();
+}
+
+void RlzLibTest::SimulateOmniboxUsage() {
+ tracker_.Observe(chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
+ NotificationService::AllSources(),
+ Details<AutocompleteLog>(NULL));
+}
+
+void RlzLibTest::SimulateHomepageUsage() {
+ NavigationEntry entry(NULL, 0, GURL(), GURL(), string16(),
+ TestRLZTracker::RLZ_PAGETRANSITION_HOME_PAGE);
+ tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+ NotificationService::AllSources(),
+ Details<NavigationEntry>(&entry));
+}
+
+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) {
+ EXPECT_EQ(expected, tracker_.pingnow_called());
+}
+
+TEST_F(RlzLibTest, RecordProductEvent) {
+ RLZTracker::RecordProductEvent(rlz_lib::CHROME, rlz_lib::CHROME_OMNIBOX,
+ rlz_lib::FIRST_SEARCH);
+
+ ExpectEventRecorded("C1F", true);
+}
+
+// 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
+//
+// 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 are:
+//
+// C1I event is recorded
+// C2I event is recorded
+// C1F event is recorded
+// C2F event is recorded
+// C1S event is recorded
+// C2S event is recorded
+// RLZ ping sent
+//
+// 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.
+
+TEST_F(RlzLibTest, QuickStopAfterStart) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", false);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", false);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(false);
+}
+
+TEST_F(RlzLibTest, DelayedInitOnly) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ InvokeDelayedInit();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", true);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", true);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStrings) {
+ RLZTracker::InitRlzDelayed(false, 20, true, true);
+ InvokeDelayedInit();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", true);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", true);
+ ExpectEventRecorded("C2F", false);
+
+ 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(rlz_lib::CHROME_OMNIBOX, kOmniboxRlzString);
+ rlz_lib::SetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE, kHomepageRlzString);
+
+ RLZTracker::InitRlzDelayed(false, 20, true, true);
+ InvokeDelayedInit();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, DelayedInitOnlyNoGoogleDefaultSearchOrHomepage) {
+ RLZTracker::InitRlzDelayed(true, 20, false, false);
+ InvokeDelayedInit();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, OmniboxUsageOnly) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ SimulateOmniboxUsage();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", false);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", true);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", false);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(false);
+}
+
+TEST_F(RlzLibTest, HomepageUsageOnly) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ SimulateHomepageUsage();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", false);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", false);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", true);
+
+ ExpectRlzPingSent(false);
+}
+
+TEST_F(RlzLibTest, UsageBeforeDelayedInit) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ SimulateOmniboxUsage();
+ SimulateHomepageUsage();
+ InvokeDelayedInit();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", true);
+ ExpectEventRecorded("C1F", true);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", true);
+ ExpectEventRecorded("C2F", true);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, OmniboxUsageAfterDelayedInit) {
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ InvokeDelayedInit();
+ SimulateOmniboxUsage();
+ SimulateHomepageUsage();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", true);
+ ExpectEventRecorded("C1F", true);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", true);
+ ExpectEventRecorded("C2F", true);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, OmniboxUsageSendsPingWhenDelayNegative) {
+ RLZTracker::InitRlzDelayed(true, -20, true, true);
+ SimulateOmniboxUsage();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", true);
+ ExpectEventRecorded("C1S", true);
+ ExpectEventRecorded("C1F", true);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", true);
+ ExpectEventRecorded("C2S", true);
+ ExpectEventRecorded("C2F", false);
+
+ ExpectRlzPingSent(true);
+}
+
+TEST_F(RlzLibTest, HomepageUsageDoesNotSendPingWhenDelayNegative) {
+ RLZTracker::InitRlzDelayed(true, -20, true, true);
+ SimulateHomepageUsage();
+
+ // Omnibox events.
+ ExpectEventRecorded("C1I", false);
+ ExpectEventRecorded("C1S", false);
+ ExpectEventRecorded("C1F", false);
+
+ // Home page events.
+ ExpectEventRecorded("C2I", false);
+ ExpectEventRecorded("C2S", false);
+ ExpectEventRecorded("C2F", true);
+
+ ExpectRlzPingSent(false);
+}
+
+TEST_F(RlzLibTest, GetAccessPointRlzOnIoThread) {
+ // Set dummy RLZ string.
+ rlz_lib::SetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, kOmniboxRlzString);
+
+ std::wstring rlz;
+
+ tracker_.set_assume_io_thread(true);
+ EXPECT_TRUE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+ EXPECT_STREQ(kOmniboxRlzString, WideToUTF8(rlz).c_str());
+}
+
+TEST_F(RlzLibTest, GetAccessPointRlzNotOnIoThread) {
+ // Set dummy RLZ string.
+ rlz_lib::SetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, kOmniboxRlzString);
+
+ std::wstring rlz;
+
+ tracker_.set_assume_io_thread(false);
+ EXPECT_FALSE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+}
+
+TEST_F(RlzLibTest, GetAccessPointRlzIsCached) {
+ // Set dummy RLZ string.
+ rlz_lib::SetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, kOmniboxRlzString);
+
+ std::wstring rlz;
+
+ tracker_.set_assume_io_thread(false);
+ EXPECT_FALSE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+
+ tracker_.set_assume_io_thread(true);
+ EXPECT_TRUE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+ EXPECT_STREQ(kOmniboxRlzString, WideToUTF8(rlz).c_str());
+
+ tracker_.set_assume_io_thread(false);
+ EXPECT_TRUE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+ EXPECT_STREQ(kOmniboxRlzString, WideToUTF8(rlz).c_str());
+}
+
+TEST_F(RlzLibTest, PingInvalidatesRlzCache) {
+ // Set dummy RLZ string.
+ rlz_lib::SetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, kOmniboxRlzString);
+
+ std::wstring rlz;
+
+ // Prime the cache.
+ tracker_.set_assume_io_thread(true);
+ EXPECT_TRUE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+ EXPECT_STREQ(kOmniboxRlzString, WideToUTF8(rlz).c_str());
+
+ // Make sure cache is valid.
+ tracker_.set_assume_io_thread(false);
+ EXPECT_TRUE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+ EXPECT_STREQ(kOmniboxRlzString, WideToUTF8(rlz).c_str());
+
+ // Perform ping.
+ RLZTracker::InitRlzDelayed(true, 20, true, true);
+ InvokeDelayedInit();
+ ExpectRlzPingSent(true);
+
+ // Make sure cache is now invalid.
+ EXPECT_FALSE(RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz));
+}
+
+TEST_F(RlzLibTest, ObserveHandlesBadArgs) {
+ NavigationEntry entry(NULL, 0, GURL(), GURL(), string16(),
+ PageTransition::LINK);
+ tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+ NotificationService::AllSources(),
+ Details<NavigationEntry>(NULL));
+ tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+ NotificationService::AllSources(),
+ Details<NavigationEntry>(&entry));
}