blob: 77d76cc896b37b06348bfe14498fd33489b7c8cf [file] [log] [blame]
// 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 "chrome/installer/util/beacons.h"
#include <memory>
#include <tuple>
#include "base/memory/ptr_util.h"
#include "base/test/test_reg_util_win.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
#include "chrome/install_static/install_details.h"
#include "chrome/install_static/install_modes.h"
#include "chrome/install_static/test/scoped_install_details.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/test_app_registration_data.h"
#include "chrome/installer/util/util_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Bool;
using ::testing::Combine;
using ::testing::Values;
using BeaconType = installer_util::Beacon::BeaconType;
using BeaconScope = installer_util::Beacon::BeaconScope;
namespace installer_util {
// A test fixture that exercises a beacon.
class BeaconTest : public ::testing::TestWithParam<
::testing::tuple<BeaconType, BeaconScope, bool>> {
protected:
static const base::char16 kBeaconName[];
BeaconTest()
: beacon_type_(::testing::get<0>(GetParam())),
beacon_scope_(::testing::get<1>(GetParam())),
system_install_(::testing::get<2>(GetParam())),
beacon_(kBeaconName,
beacon_type_,
beacon_scope_,
system_install_,
app_registration_data_) {}
void SetUp() override {
// Override the registry so that tests can freely push state to it.
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
}
TestAppRegistrationData app_registration_data_;
BeaconType beacon_type_;
BeaconScope beacon_scope_;
bool system_install_;
Beacon beacon_;
private:
registry_util::RegistryOverrideManager registry_override_manager_;
};
// static
const base::char16 BeaconTest::kBeaconName[] = L"TestBeacon";
// Nothing in the regsitry, so the beacon should not exist.
TEST_P(BeaconTest, GetNonExistant) {
ASSERT_TRUE(beacon_.Get().is_null());
}
// Updating and then getting the beacon should return a value, and that it is
// within range.
TEST_P(BeaconTest, UpdateAndGet) {
base::Time before(base::Time::Now());
beacon_.Update();
base::Time after(base::Time::Now());
base::Time beacon_time(beacon_.Get());
ASSERT_FALSE(beacon_time.is_null());
ASSERT_LE(before, beacon_time);
ASSERT_GE(after, beacon_time);
}
// Tests that updating a first beacon only updates it the first time, but doing
// so for a last beacon always updates.
TEST_P(BeaconTest, UpdateTwice) {
beacon_.Update();
base::Time beacon_time(beacon_.Get());
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
beacon_.Update();
if (beacon_type_ == BeaconType::FIRST) {
ASSERT_EQ(beacon_time, beacon_.Get());
} else {
ASSERT_NE(beacon_time, beacon_.Get());
}
}
// Tests that the beacon is written into the proper location in the registry.
TEST_P(BeaconTest, Location) {
beacon_.Update();
HKEY right_root = system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
HKEY wrong_root = system_install_ ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
base::string16 right_key;
base::string16 wrong_key;
base::string16 value_name;
if (beacon_scope_ == BeaconScope::PER_INSTALL || !system_install_) {
value_name = kBeaconName;
right_key = app_registration_data_.GetStateKey();
wrong_key = app_registration_data_.GetStateMediumKey();
} else {
ASSERT_TRUE(base::win::GetUserSidString(&value_name));
right_key =
app_registration_data_.GetStateMediumKey() + L"\\" + kBeaconName;
wrong_key = app_registration_data_.GetStateKey();
}
// Keys should not exist in the wrong root or in the right root but wrong key.
ASSERT_FALSE(base::win::RegKey(wrong_root, right_key.c_str(),
KEY_READ).Valid()) << right_key;
ASSERT_FALSE(base::win::RegKey(wrong_root, wrong_key.c_str(),
KEY_READ).Valid()) << wrong_key;
ASSERT_FALSE(base::win::RegKey(right_root, wrong_key.c_str(),
KEY_READ).Valid()) << wrong_key;
// The right key should exist.
base::win::RegKey key(right_root, right_key.c_str(), KEY_READ);
ASSERT_TRUE(key.Valid()) << right_key;
// And should have the value.
ASSERT_TRUE(key.HasValue(value_name.c_str())) << value_name;
}
// Run the tests for all combinations of beacon type, scope, and install level.
INSTANTIATE_TEST_CASE_P(BeaconTest,
BeaconTest,
Combine(Values(BeaconType::FIRST, BeaconType::LAST),
Values(BeaconScope::PER_USER,
BeaconScope::PER_INSTALL),
Bool()));
class DefaultBrowserBeaconTest
: public ::testing::TestWithParam<
std::tuple<install_static::InstallConstantIndex, const char*>> {
protected:
using Super = ::testing::TestWithParam<
std::tuple<install_static::InstallConstantIndex, const char*>>;
void SetUp() override {
Super::SetUp();
install_static::InstallConstantIndex mode_index;
const char* level;
std::tie(mode_index, level) = GetParam();
system_install_ = (std::string(level) != "user");
// Configure InstallDetails for the test.
scoped_install_details_ =
base::MakeUnique<install_static::ScopedInstallDetails>(system_install_,
mode_index);
// Override the registry so that tests can freely push state to it.
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
// Ensure that IsPerUserInstall returns the proper value.
ASSERT_EQ(!system_install_, InstallUtil::IsPerUserInstall());
distribution_ = BrowserDistribution::GetDistribution();
}
bool system_install_ = false;
BrowserDistribution* distribution_ = nullptr;
private:
std::unique_ptr<install_static::ScopedInstallDetails> scoped_install_details_;
registry_util::RegistryOverrideManager registry_override_manager_;
};
// Tests that the default browser beacons work as expected.
TEST_P(DefaultBrowserBeaconTest, All) {
std::unique_ptr<Beacon> last_was_default(MakeLastWasDefaultBeacon(
system_install_, distribution_->GetAppRegistrationData()));
std::unique_ptr<Beacon> first_not_default(MakeFirstNotDefaultBeacon(
system_install_, distribution_->GetAppRegistrationData()));
ASSERT_TRUE(last_was_default->Get().is_null());
ASSERT_TRUE(first_not_default->Get().is_null());
// Chrome is not default.
UpdateDefaultBrowserBeaconWithState(distribution_, ShellUtil::NOT_DEFAULT);
ASSERT_TRUE(last_was_default->Get().is_null());
ASSERT_FALSE(first_not_default->Get().is_null());
// Then it is.
UpdateDefaultBrowserBeaconWithState(distribution_, ShellUtil::IS_DEFAULT);
ASSERT_FALSE(last_was_default->Get().is_null());
ASSERT_TRUE(first_not_default->Get().is_null());
// It still is.
UpdateDefaultBrowserBeaconWithState(distribution_, ShellUtil::IS_DEFAULT);
ASSERT_FALSE(last_was_default->Get().is_null());
ASSERT_TRUE(first_not_default->Get().is_null());
// Now it's not again.
UpdateDefaultBrowserBeaconWithState(distribution_, ShellUtil::NOT_DEFAULT);
ASSERT_FALSE(last_was_default->Get().is_null());
ASSERT_FALSE(first_not_default->Get().is_null());
// And it still isn't.
UpdateDefaultBrowserBeaconWithState(distribution_, ShellUtil::NOT_DEFAULT);
ASSERT_FALSE(last_was_default->Get().is_null());
ASSERT_FALSE(first_not_default->Get().is_null());
}
#if defined(GOOGLE_CHROME_BUILD)
// Stable supports user and system levels.
INSTANTIATE_TEST_CASE_P(
Stable,
DefaultBrowserBeaconTest,
testing::Combine(testing::Values(install_static::STABLE_INDEX),
testing::Values("user", "system")));
// Canary is only at user level.
INSTANTIATE_TEST_CASE_P(
Canary,
DefaultBrowserBeaconTest,
testing::Combine(testing::Values(install_static::CANARY_INDEX),
testing::Values("user")));
#else // GOOGLE_CHROME_BUILD
// Chromium supports user and system levels.
INSTANTIATE_TEST_CASE_P(
Chromium,
DefaultBrowserBeaconTest,
testing::Combine(testing::Values(install_static::CHROMIUM_INDEX),
testing::Values("user", "system")));
#endif // GOOGLE_CHROME_BUILD
} // namespace installer_util