| // 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. |
| // |
| // A test application for the RLZ library. |
| // |
| // These tests should not be executed on the build server: |
| // - They assert for the failed cases. |
| // - They modify machine state (registry). |
| // |
| // These tests require write access to HKLM and HKCU. |
| // |
| // The "GGLA" brand is used to test the normal code flow of the code, and the |
| // "TEST" brand is used to test the supplementary brand code code flow. |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/message_loop/message_pump_type.h" |
| #include "base/posix/eintr_wrapper.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/task_environment.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "rlz/lib/financial_ping.h" |
| #include "rlz/lib/lib_values.h" |
| #include "rlz/lib/net_response_check.h" |
| #include "rlz/lib/rlz_lib.h" |
| #include "rlz/lib/rlz_lib_clear.h" |
| #include "rlz/lib/rlz_value_store.h" |
| #include "rlz/test/rlz_test_helpers.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| #if defined(OS_WIN) |
| #include <Windows.h> |
| #include "rlz/win/lib/machine_deal.h" |
| #endif |
| |
| #if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET) |
| #include "base/mac/scoped_nsautorelease_pool.h" |
| #include "base/threading/thread.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "base/files/important_file_writer.h" |
| #include "base/stl_util.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h" |
| #include "rlz/chromeos/lib/rlz_value_store_chromeos.h" |
| #endif |
| |
| class MachineDealCodeHelper |
| #if defined(OS_WIN) |
| : public rlz_lib::MachineDealCode |
| #endif |
| { |
| public: |
| static bool Clear() { |
| #if defined(OS_WIN) |
| return rlz_lib::MachineDealCode::Clear(); |
| #else |
| return true; |
| #endif |
| } |
| |
| private: |
| MachineDealCodeHelper() = default; |
| ~MachineDealCodeHelper() = default; |
| }; |
| |
| class RlzLibTest : public RlzLibTestBase { |
| protected: |
| void FakeGoodPingResponse(rlz_lib::Product product, |
| const rlz_lib::AccessPoint* access_points, |
| const char* product_signature, |
| const char* product_brand, |
| const char* product_id, |
| const char* product_lang, |
| bool exclude_machine_id, |
| network::TestURLLoaderFactory* url_loader_factory) { |
| const char kGoodPingResponses[] = |
| "version: 3.0.914.7250\r\n" |
| "url: " |
| "http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n" |
| "rlzT4 1T4_____en__251\r\n" |
| "rlzT4: 1T4_____en__252\r\n" |
| "rlz\r\n" |
| "crc32: D6FD55A3"; |
| std::string request; |
| EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest( |
| product, access_points, product_signature, product_brand, product_id, |
| product_lang, exclude_machine_id, &request)); |
| std::string url = base::StringPrintf( |
| "https://%s%s", rlz_lib::kFinancialServer, request.c_str()); |
| url_loader_factory->AddResponse(url, kGoodPingResponses); |
| } |
| |
| base::test::TaskEnvironment task_environment_; |
| }; |
| |
| TEST_F(RlzLibTest, RecordProductEvent) { |
| char cgi_50[50]; |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S", cgi_50); |
| |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S,W1I", cgi_50); |
| |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S,W1I", cgi_50); |
| } |
| |
| TEST_F(RlzLibTest, ClearProductEvent) { |
| char cgi_50[50]; |
| |
| // Clear 1 of 1 events. |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S", cgi_50); |
| EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("", cgi_50); |
| |
| // Clear 1 of 2 events. |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S,W1I", cgi_50); |
| EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=W1I", cgi_50); |
| |
| // Clear a non-recorded event. |
| EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IETB_SEARCH_BOX, rlz_lib::FIRST_SEARCH)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=W1I", cgi_50); |
| } |
| |
| |
| TEST_F(RlzLibTest, GetProductEventsAsCgi) { |
| char cgi_50[50]; |
| char cgi_1[1]; |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_1, 1)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S,W1I", cgi_50); |
| } |
| |
| TEST_F(RlzLibTest, ClearAllAllProductEvents) { |
| char cgi_50[50]; |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S", cgi_50); |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("", cgi_50); |
| } |
| |
| TEST_F(RlzLibTest, SetAccessPointRlz) { |
| char rlz_50[50]; |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("", rlz_50); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("IeTbRlz", rlz_50); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F(RlzLibTest, SetAccessPointRlzOnlyOnce) { |
| // On Chrome OS, and RLZ string can ne set only once. |
| char rlz_50[50]; |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "First")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("First", rlz_50); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "Second")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("First", rlz_50); |
| } |
| |
| TEST_F(RlzLibTest, UpdateExistingAccessPointRlz) { |
| const std::string json_data = R"({ |
| "access_points": { |
| "CA": { |
| "_": "1CANPEC_enUS818" |
| }, |
| "CB": { |
| "_": "1CBNPE" |
| }, |
| "CC": { |
| "_": "1CANPEC_enUS818" |
| } |
| }, |
| "product_events": { |
| "C": { |
| "_": [ "CAS" ] |
| } |
| } |
| })"; |
| ASSERT_TRUE(base::ImportantFileWriter::WriteFileAtomically( |
| base::FilePath(rlz_lib::testing::RlzStoreFilenameStr()), json_data)); |
| // Verify that the initial values are read correctly. |
| char data[50]; |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_OMNIBOX, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| EXPECT_TRUE( |
| rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_HOME_PAGE, data, 50)); |
| EXPECT_STREQ("1CBNPE", data); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_APP_LIST, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, data, 50)); |
| EXPECT_STREQ("events=CAS", data); |
| |
| // Verify that if the brand code doesn't consist of four letters, none of the |
| // access point RLZ strings is updated. |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_OMNIBOX, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| EXPECT_TRUE( |
| rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_HOME_PAGE, data, 50)); |
| EXPECT_STREQ("1CBNPE", data); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_APP_LIST, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| |
| // Update the RLZ strings with a valid brand code. Verify that the RLZ string |
| // is updated if it also has valid format. |
| EXPECT_TRUE(rlz_lib::UpdateExistingAccessPointRlz("BMGD")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_OMNIBOX, data, 50)); |
| EXPECT_STREQ("1CABMGD_enUS818", data); |
| // The RLZ string remains unchanged if it has fewer than seven characters. |
| EXPECT_TRUE( |
| rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_HOME_PAGE, data, 50)); |
| EXPECT_STREQ("1CBNPE", data); |
| // The RLZ string remains unchanged if the access point names don't match. |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_APP_LIST, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| // The product events remain unchanged. |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, data, 50)); |
| EXPECT_STREQ("events=CAS", data); |
| |
| // Verify a second update is no-op. |
| EXPECT_FALSE(rlz_lib::UpdateExistingAccessPointRlz("BMGD")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_OMNIBOX, data, 50)); |
| EXPECT_STREQ("1CABMGD_enUS818", data); |
| EXPECT_TRUE( |
| rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_HOME_PAGE, data, 50)); |
| EXPECT_STREQ("1CBNPE", data); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::CHROMEOS_APP_LIST, data, 50)); |
| EXPECT_STREQ("1CANPEC_enUS818", data); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, data, 50)); |
| EXPECT_STREQ("events=CAS", data); |
| } |
| #endif |
| |
| TEST_F(RlzLibTest, GetAccessPointRlz) { |
| char rlz_1[1]; |
| char rlz_50[50]; |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_1, 1)); |
| EXPECT_STREQ("", rlz_1); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz")); |
| EXPECT_FALSE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_1, 1)); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("IeTbRlz", rlz_50); |
| } |
| |
| TEST_F(RlzLibTest, GetPingParams) { |
| MachineDealCodeHelper::Clear(); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, |
| "TbRlzValue")); |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IE_HOME_PAGE, "")); |
| |
| char cgi[2048]; |
| rlz_lib::AccessPoint points[] = |
| {rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT, |
| rlz_lib::NO_ACCESS_POINT}; |
| |
| EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points, |
| cgi, 2048)); |
| EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue", cgi); |
| |
| #if defined(OS_WIN) |
| EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); |
| #define DCC_PARAM "&dcc=dcc_value" |
| #else |
| #define DCC_PARAM "" |
| #endif |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "")); |
| EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points, |
| cgi, 2048)); |
| EXPECT_STREQ("rep=2&rlz=T4:" DCC_PARAM, cgi); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, |
| "TbRlzValue")); |
| EXPECT_FALSE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points, |
| cgi, 23 + strlen(DCC_PARAM))); |
| EXPECT_STREQ("", cgi); |
| EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points, |
| cgi, 24 + strlen(DCC_PARAM))); |
| EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue" DCC_PARAM, cgi); |
| |
| EXPECT_TRUE(GetAccessPointRlz(rlz_lib::IE_HOME_PAGE, cgi, 2048)); |
| points[2] = rlz_lib::IE_HOME_PAGE; |
| EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points, |
| cgi, 2048)); |
| EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue" DCC_PARAM, cgi); |
| } |
| |
| TEST_F(RlzLibTest, IsPingResponseValid) { |
| const char* kBadPingResponses[] = { |
| // No checksum. |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n", |
| |
| // Invalid checksum. |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n" |
| "rlzT4 1T4_____en__251\r\n" |
| "rlzT4: 1T4_____en__252\r\n" |
| "rlz\r\n" |
| "crc32: B12CC79A", |
| |
| // Misplaced checksum. |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n" |
| "crc32: B12CC79C\r\n" |
| "rlzT4 1T4_____en__251\r\n" |
| "rlzT4: 1T4_____en__252\r\n" |
| "rlz\r\n", |
| |
| NULL |
| }; |
| |
| const char* kGoodPingResponses[] = { |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n" |
| "rlzT4 1T4_____en__251\r\n" |
| "rlzT4: 1T4_____en__252\r\n" |
| "rlz\r\n" |
| "crc32: D6FD55A3", |
| |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" |
| "rlzXX: 1R1_____en__250\r\n" |
| "rlzT4 1T4_____en__251\r\n" |
| "rlzT4: 1T4_____en__252\r\n" |
| "rlz\r\n" |
| "crc32: D6FD55A3\r\n" |
| "extradata: not checksummed", |
| |
| NULL |
| }; |
| |
| for (int i = 0; kBadPingResponses[i]; i++) |
| EXPECT_FALSE(rlz_lib::IsPingResponseValid(kBadPingResponses[i], NULL)); |
| |
| for (int i = 0; kGoodPingResponses[i]; i++) |
| EXPECT_TRUE(rlz_lib::IsPingResponseValid(kGoodPingResponses[i], NULL)); |
| } |
| |
| TEST_F(RlzLibTest, ParsePingResponse) { |
| const char* kPingResponse = |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlz: 1R1_____en__252\r\n" // Invalid RLZ - no access point. |
| "rlzXX: 1R1_____en__250\r\n" // Invalid RLZ - bad access point. |
| "rlzT4 1T4_____en__251\r\n" // Invalid RLZ - missing colon. |
| "rlzT4: 1T4_____en__252\r\n" // GoodRLZ. |
| "events: I7S,W1I\r\n" // Clear all events. |
| "rlz\r\n" |
| "dcc: dcc_value\r\n" |
| "crc32: F9070F81"; |
| |
| #if defined(OS_WIN) |
| EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value2")); |
| #endif |
| |
| // Record some product events to check that they get cleared. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| #if defined(OS_WIN) |
| EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); |
| #endif |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse)); |
| |
| char value[50]; |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, value, 50)); |
| EXPECT_STREQ("1T4_____en__252", value); |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("", value); |
| |
| const char* kPingResponse2 = |
| "rlzT4: 1T4_____de__253 \r\n" // Good with extra spaces. |
| "crc32: 321334F5\r\n"; |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse2)); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, value, 50)); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // On Chrome OS, the RLZ string is not modified by response once set. |
| EXPECT_STREQ("1T4_____en__252", value); |
| #else |
| EXPECT_STREQ("1T4_____de__253", value); |
| #endif |
| |
| const char* kPingResponse3 = |
| "crc32: 0\r\n"; // Good RLZ - empty response. |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse3)); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // On Chrome OS, the RLZ string is not modified by response once set. |
| EXPECT_STREQ("1T4_____en__252", value); |
| #else |
| EXPECT_STREQ("1T4_____de__253", value); |
| #endif |
| } |
| |
| // Test whether a stateful event will only be sent in financial pings once. |
| TEST_F(RlzLibTest, ParsePingResponseWithStatefulEvents) { |
| const char* kPingResponse = |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlzT4: 1T4_____en__252\r\n" // GoodRLZ. |
| "events: I7S,W1I\r\n" // Clear all events. |
| "stateful-events: W1I\r\n" // W1I as an stateful event. |
| "rlz\r\n" |
| "dcc: dcc_value\r\n" |
| "crc32: 55191759"; |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| |
| // Record some product events to check that they get cleared. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz( |
| rlz_lib::IETB_SEARCH_BOX, "TbRlzValue")); |
| |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse)); |
| |
| // Check all the events sent earlier are cleared. |
| char value[50]; |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("", value); |
| |
| // Record both events (one is stateless and the other is stateful) again. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| // Check the stateful event won't be sent again while the stateless one will. |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("events=I7S", value); |
| |
| // Test that stateful events are cleared by ClearAllProductEvents(). After |
| // calling it, trying to record a stateful again should result in it being |
| // recorded again. |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("events=W1I", value); |
| } |
| |
| class URLLoaderFactoryRAII { |
| public: |
| URLLoaderFactoryRAII(network::mojom::URLLoaderFactory* factory) { |
| rlz_lib::SetURLLoaderFactory(factory); |
| } |
| ~URLLoaderFactoryRAII() { rlz_lib::SetURLLoaderFactory(nullptr); } |
| }; |
| |
| TEST_F(RlzLibTest, SendFinancialPing) { |
| // rlz_lib::SendFinancialPing fails when this is set. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| #if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET) |
| #if defined(OS_APPLE) |
| base::mac::ScopedNSAutoreleasePool pool; |
| #endif |
| |
| network::TestURLLoaderFactory test_url_loader_factory; |
| |
| URLLoaderFactoryRAII set_factory( |
| test_url_loader_factory.GetSafeWeakWrapper().get()); |
| #endif |
| |
| MachineDealCodeHelper::Clear(); |
| #if defined(OS_WIN) |
| EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); |
| #endif |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, |
| "TbRlzValue")); |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| rlz_lib::AccessPoint points[] = |
| {rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT, |
| rlz_lib::NO_ACCESS_POINT}; |
| |
| // Excluding machine id from requests so that a stable URL is used and |
| // this test can use TestURLLoaderFactory. |
| FakeGoodPingResponse(rlz_lib::TOOLBAR_NOTIFIER, points, "swg", "GGLA", |
| "SwgProductId1234", "en-UK", |
| /* exclude_machine_id */ true, &test_url_loader_factory); |
| |
| rlz_lib::SendFinancialPing(rlz_lib::TOOLBAR_NOTIFIER, points, "swg", "GGLA", |
| "SwgProductId1234", "en-UK", |
| /* exclude_machine_id */ true, |
| /* skip_time_check */ true); |
| } |
| |
| #if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET) |
| |
| void ResetURLLoaderFactory() { |
| rlz_lib::SetURLLoaderFactory(nullptr); |
| } |
| |
| TEST_F(RlzLibTest, SendFinancialPingDuringShutdown) { |
| // rlz_lib::SendFinancialPing fails when this is set. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| #if defined(OS_APPLE) |
| base::mac::ScopedNSAutoreleasePool pool; |
| #endif |
| |
| base::Thread::Options options; |
| options.message_pump_type = base::MessagePumpType::IO; |
| |
| base::Thread io_thread("rlz_unittest_io_thread"); |
| ASSERT_TRUE(io_thread.StartWithOptions(options)); |
| |
| network::TestURLLoaderFactory test_url_loader_factory; |
| URLLoaderFactoryRAII set_factory( |
| test_url_loader_factory.GetSafeWeakWrapper().get()); |
| |
| rlz_lib::AccessPoint points[] = |
| {rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT, |
| rlz_lib::NO_ACCESS_POINT}; |
| rlz_lib::test::ResetSendFinancialPingInterrupted(); |
| EXPECT_FALSE(rlz_lib::test::WasSendFinancialPingInterrupted()); |
| |
| io_thread.task_runner()->PostTask(FROM_HERE, |
| base::BindOnce(&ResetURLLoaderFactory)); |
| |
| rlz_lib::SendFinancialPing(rlz_lib::TOOLBAR_NOTIFIER, points, "swg", "GGLA", |
| "SwgProductId1234", "en-UK", |
| /* exclude_machine_id */ false, |
| /* skip_time_check */ true); |
| |
| EXPECT_TRUE(rlz_lib::test::WasSendFinancialPingInterrupted()); |
| rlz_lib::test::ResetSendFinancialPingInterrupted(); |
| } |
| #endif |
| |
| TEST_F(RlzLibTest, ClearProductState) { |
| MachineDealCodeHelper::Clear(); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, |
| "TbRlzValue")); |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::GD_DESKBAND, |
| "GdbRlzValue")); |
| |
| rlz_lib::AccessPoint points[] = |
| { rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT }; |
| |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IETB_SEARCH_BOX, rlz_lib::INSTALL)); |
| |
| rlz_lib::AccessPoint points2[] = |
| { rlz_lib::IETB_SEARCH_BOX, |
| rlz_lib::GD_DESKBAND, |
| rlz_lib::NO_ACCESS_POINT }; |
| |
| char cgi[2048]; |
| EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points2, |
| cgi, 2048)); |
| EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue,D1:GdbRlzValue", cgi); |
| |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi, 2048)); |
| std::string events(cgi); |
| EXPECT_LT(0u, events.find("I7S")); |
| EXPECT_LT(0u, events.find("T4I")); |
| EXPECT_LT(0u, events.find("T4R")); |
| |
| rlz_lib::ClearProductState(rlz_lib::TOOLBAR_NOTIFIER, points); |
| |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, |
| cgi, 2048)); |
| EXPECT_STREQ("", cgi); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::GD_DESKBAND, |
| cgi, 2048)); |
| EXPECT_STREQ("GdbRlzValue", cgi); |
| |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi, 2048)); |
| EXPECT_STREQ("", cgi); |
| } |
| |
| #if defined(OS_WIN) |
| template<class T> |
| class typed_buffer_ptr { |
| std::unique_ptr<char[]> buffer_; |
| |
| public: |
| typed_buffer_ptr() { |
| } |
| |
| explicit typed_buffer_ptr(size_t size) : buffer_(new char[size]) { |
| } |
| |
| void reset(size_t size) { |
| buffer_.reset(new char[size]); |
| } |
| |
| operator T*() { |
| return reinterpret_cast<T*>(buffer_.get()); |
| } |
| }; |
| |
| namespace rlz_lib { |
| bool HasAccess(PSID sid, ACCESS_MASK access_mask, ACL* dacl); |
| } |
| |
| bool EmptyAcl(ACL* acl) { |
| ACL_SIZE_INFORMATION info; |
| bool ret = GetAclInformation(acl, &info, sizeof(info), AclSizeInformation); |
| EXPECT_TRUE(ret); |
| |
| for (DWORD i = 0; i < info.AceCount && ret; ++i) { |
| ret = DeleteAce(acl, 0); |
| EXPECT_TRUE(ret); |
| } |
| |
| return ret; |
| } |
| |
| TEST_F(RlzLibTest, HasAccess) { |
| // Create a SID that represents ALL USERS. |
| DWORD users_sid_size = SECURITY_MAX_SID_SIZE; |
| typed_buffer_ptr<SID> users_sid(users_sid_size); |
| CreateWellKnownSid(WinBuiltinUsersSid, NULL, users_sid, &users_sid_size); |
| |
| // RLZ always asks for KEY_ALL_ACCESS access to the key. This is what we |
| // test here. |
| |
| // No ACL mean no access. |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, NULL)); |
| |
| // Create an ACL for these tests. |
| const DWORD kMaxAclSize = 1024; |
| typed_buffer_ptr<ACL> dacl(kMaxAclSize); |
| InitializeAcl(dacl, kMaxAclSize, ACL_REVISION); |
| |
| // Empty DACL mean no access. |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // ACE without all needed privileges should mean no access. |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_READ, users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // ACE without all needed privileges should mean no access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_WRITE, users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // A deny ACE before an allow ACE should not give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // A deny ACE before an allow ACE should not give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_READ, users_sid)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| |
| // An allow ACE without all required bits should not give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_WRITE, users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // An allow ACE with all required bits should give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // A deny ACE after an allow ACE should not give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_READ, users_sid)); |
| EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // An inherit-only allow ACE should not give access. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessAllowedAceEx(dacl, ACL_REVISION, INHERIT_ONLY_ACE, |
| KEY_ALL_ACCESS, users_sid)); |
| EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| |
| // An inherit-only deny ACE should not apply. |
| EXPECT_TRUE(EmptyAcl(dacl)); |
| EXPECT_TRUE(AddAccessDeniedAceEx(dacl, ACL_REVISION, INHERIT_ONLY_ACE, |
| KEY_ALL_ACCESS, users_sid)); |
| EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS, |
| users_sid)); |
| EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl)); |
| } |
| #endif |
| |
| TEST_F(RlzLibTest, BrandingRecordProductEvent) { |
| // Don't run these tests if a supplementary brand is already in place. That |
| // way we can control the branding. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| char cgi_50[50]; |
| |
| // Record different events for the same product with diffrent branding, and |
| // make sure that the information remains separate. |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| } |
| |
| // Test that recording events with the default brand and a supplementary |
| // brand don't overwrite each other. |
| |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S", cgi_50); |
| |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7I", cgi_50); |
| } |
| |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| cgi_50, 50)); |
| EXPECT_STREQ("events=I7S", cgi_50); |
| } |
| |
| TEST_F(RlzLibTest, BrandingSetAccessPointRlz) { |
| // Don't run these tests if a supplementary brand is already in place. That |
| // way we can control the branding. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| char rlz_50[50]; |
| |
| // Test that setting RLZ strings with the default brand and a supplementary |
| // brand don't overwrite each other. |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("IeTbRlz", rlz_50); |
| |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| |
| EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "SuppRlz")); |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, |
| 50)); |
| EXPECT_STREQ("SuppRlz", rlz_50); |
| } |
| |
| EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50)); |
| EXPECT_STREQ("IeTbRlz", rlz_50); |
| |
| } |
| |
| TEST_F(RlzLibTest, BrandingWithStatefulEvents) { |
| // Don't run these tests if a supplementary brand is already in place. That |
| // way we can control the branding. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| const char* kPingResponse = |
| "version: 3.0.914.7250\r\n" |
| "url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n" |
| "launch-action: custom-action\r\n" |
| "launch-target: SearchWithGoogleUpdate.exe\r\n" |
| "signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n" |
| "rlzT4: 1T4_____en__252\r\n" // GoodRLZ. |
| "events: I7S,W1I\r\n" // Clear all events. |
| "stateful-events: W1I\r\n" // W1I as an stateful event. |
| "rlz\r\n" |
| "dcc: dcc_value\r\n" |
| "crc32: 55191759"; |
| |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER)); |
| } |
| |
| // Record some product events for the default and supplementary brand. |
| // Check that they get cleared only for the default brand. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| } |
| |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse)); |
| |
| // Check all the events sent earlier are cleared only for default brand. |
| char value[50]; |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("", value); |
| |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("events=I7S,W1I", value); |
| } |
| |
| // Record both events (one is stateless and the other is stateful) again. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL)); |
| |
| // Check the stateful event won't be sent again while the stateless one will. |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("events=I7S", value); |
| |
| { |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, |
| kPingResponse)); |
| |
| EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("", value); |
| } |
| |
| EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER, |
| value, 50)); |
| EXPECT_STREQ("events=I7S", value); |
| } |
| |
| #if defined(OS_POSIX) |
| class ReadonlyRlzDirectoryTest : public RlzLibTestNoMachineState { |
| protected: |
| void SetUp() override; |
| }; |
| |
| void ReadonlyRlzDirectoryTest::SetUp() { |
| RlzLibTestNoMachineState::SetUp(); |
| // Make the rlz directory non-writeable. |
| int chmod_result = |
| chmod(m_rlz_test_helper_.temp_dir_.GetPath().value().c_str(), 0500); |
| ASSERT_EQ(0, chmod_result); |
| } |
| |
| TEST_F(ReadonlyRlzDirectoryTest, WriteFails) { |
| // The rlz test runner runs every test twice: Once normally, and once with |
| // a SupplementaryBranding on the stack. In the latter case, the rlz lock |
| // has already been acquired before the rlz directory got changed to |
| // read-only, which makes this test pointless. So run it only in the first |
| // pass. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE)); |
| } |
| |
| // Regression test for http://crbug.com/121255 |
| TEST_F(ReadonlyRlzDirectoryTest, SupplementaryBrandingDoesNotCrash) { |
| // See the comment at the top of WriteFails. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
| } |
| |
| // Regression test for http://crbug.com/141108 |
| TEST_F(RlzLibTest, ConcurrentStoreAccessWithProcessExitsWhileLockHeld) { |
| // See the comment at the top of WriteFails. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| std::vector<pid_t> pids; |
| for (int i = 0; i < 10; ++i) { |
| pid_t pid = fork(); |
| ASSERT_NE(-1, pid); |
| if (pid == 0) { |
| // Child. |
| { |
| // SupplementaryBranding is a RAII object for the rlz lock. |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| |
| // Simulate a crash while holding the lock in some of the children. |
| if (i > 0 && i % 3 == 0) |
| _exit(0); |
| |
| // Note: Since this is in a forked child, a failing expectation won't |
| // make the test fail. It does however cause lots of "check failed" |
| // error output. The parent process will then check the exit code |
| // below to make the test fail. |
| bool success = rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL); |
| EXPECT_TRUE(success); |
| _exit(success ? 0 : 1); |
| } |
| } else { |
| // Parent. |
| pids.push_back(pid); |
| } |
| } |
| |
| int status; |
| for (size_t i = 0; i < pids.size(); ++i) { |
| if (HANDLE_EINTR(waitpid(pids[i], &status, 0)) != -1) |
| EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); |
| } |
| |
| // No child should have the lock at this point, not even the crashed ones. |
| EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
| } |
| |
| TEST_F(RlzLibTest, LockAcquistionSucceedsButStoreFileCannotBeCreated) { |
| // See the comment at the top of WriteFails. |
| if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
| return; |
| |
| // Make sure to use a brand new directory for this test, since |
| // RlzLibTest::SetUp() will have created a store file to setup the tests. |
| m_rlz_test_helper_.Reset(); |
| |
| // Create a directory where the rlz file is supposed to appear. This way, |
| // the lock file can be created successfully, but creation of the rlz file |
| // itself will fail. |
| int mkdir_result = mkdir(rlz_lib::testing::RlzStoreFilenameStr().c_str(), |
| 0500); |
| ASSERT_EQ(0, mkdir_result); |
| |
| rlz_lib::SupplementaryBranding branding("TEST"); |
| EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
| rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
| } |
| |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| class TestDebugDaemonClient : public chromeos::FakeDebugDaemonClient { |
| public: |
| TestDebugDaemonClient() = default; |
| ~TestDebugDaemonClient() override = default; |
| |
| int num_set_rlz_ping_sent() const { return num_set_rlz_ping_sent_; } |
| |
| // Sets the result returned by the callback in order to test both success and |
| // failure cases. |
| void set_default_result(bool default_result) { |
| default_result_ = default_result; |
| } |
| |
| void SetRlzPingSent(SetRlzPingSentCallback callback) override { |
| ++num_set_rlz_ping_sent_; |
| std::move(callback).Run(default_result_); |
| } |
| |
| private: |
| int num_set_rlz_ping_sent_ = 0; |
| bool default_result_; |
| DISALLOW_COPY_AND_ASSIGN(TestDebugDaemonClient); |
| }; |
| |
| TEST_F(RlzLibTest, SetRlzPingSent) { |
| TestDebugDaemonClient* debug_daemon_client = new TestDebugDaemonClient; |
| chromeos::DBusThreadManager::GetSetterForTesting()->SetDebugDaemonClient( |
| std::unique_ptr<chromeos::DebugDaemonClient>(debug_daemon_client)); |
| const char* kPingResponse = |
| "stateful-events: CAF\r\n" |
| "crc32: 3BB2FEAE\r\n"; |
| |
| // Verify that a |SetRlzPingSent| dbus call is made and it's made only once |
| // if success status is returned. |
| debug_daemon_client->set_default_result(true); |
| EXPECT_TRUE( |
| rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, kPingResponse)); |
| EXPECT_EQ(debug_daemon_client->num_set_rlz_ping_sent(), 1); |
| |
| // Verify that a maximum of |kMaxRetryCount| times of attempts are made if |
| // |SetRlzPingSent| returns failure status. |
| debug_daemon_client->set_default_result(false); |
| EXPECT_TRUE( |
| rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER, kPingResponse)); |
| EXPECT_EQ(debug_daemon_client->num_set_rlz_ping_sent(), |
| 1 + rlz_lib::RlzValueStoreChromeOS::kMaxRetryCount); |
| } |
| |
| TEST_F(RlzLibTest, NoRecordCAFEvent) { |
| // Setup as if a new machine where "should send RLZ" is true. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueTrue); |
| |
| // Record a first search event, make sure it is written correctly. |
| rlz_lib::RecordProductEvent(rlz_lib::CHROME, rlz_lib::CHROMEOS_OMNIBOX, |
| rlz_lib::FIRST_SEARCH); |
| char cgi[256]; |
| EXPECT_TRUE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| EXPECT_NE(nullptr, strstr(cgi, "CAF")); |
| |
| // Simulate another user on the machine sending the RLZ ping, so "should send |
| // RLZ" is now false. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueFalse); |
| |
| // The first search event should no longer appear, so there are no events |
| // to report. |
| EXPECT_FALSE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| |
| // The event should be permanently deleted, so setting the flag back to |
| // true should still not return the event. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueTrue); |
| EXPECT_FALSE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| } |
| |
| TEST_F(RlzLibTest, NoRecordCAFEvent2) { |
| // Setup as if a new machine where "should send RLZ" is true. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueTrue); |
| |
| // Record install and first search events, make sure they are written. |
| rlz_lib::RecordProductEvent(rlz_lib::CHROME, rlz_lib::CHROMEOS_OMNIBOX, |
| rlz_lib::INSTALL); |
| rlz_lib::RecordProductEvent(rlz_lib::CHROME, rlz_lib::CHROMEOS_OMNIBOX, |
| rlz_lib::FIRST_SEARCH); |
| char cgi[256]; |
| EXPECT_TRUE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| EXPECT_NE(nullptr, strstr(cgi, "CAF")); |
| EXPECT_NE(nullptr, strstr(cgi, "CAI")); |
| |
| // Simulate another user on the machine sending the RLZ ping, so "should send |
| // RLZ" is now false. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueFalse); |
| |
| // Only the "CAI" event should appear. |
| EXPECT_TRUE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| EXPECT_NE(nullptr, strstr(cgi, "CAI")); |
| |
| // The event should be permanently deleted, so setting the flag back to |
| // true should still not return the "CAF" event. |
| statistics_provider_->SetMachineStatistic( |
| chromeos::system::kShouldSendRlzPingKey, |
| chromeos::system::kShouldSendRlzPingValueTrue); |
| EXPECT_TRUE( |
| rlz_lib::GetProductEventsAsCgi(rlz_lib::CHROME, cgi, base::size(cgi))); |
| EXPECT_NE(nullptr, strstr(cgi, "CAI")); |
| } |
| #endif |