1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/installer/util/beacons.h"
6
7 #include <memory>
8 #include <tuple>
9
10 #include "base/test/test_reg_util_win.h"
11 #include "base/test/test_timeouts.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/win/registry.h"
14 #include "base/win/win_util.h"
15 #include "build/branding_buildflags.h"
16 #include "chrome/install_static/install_details.h"
17 #include "chrome/install_static/install_modes.h"
18 #include "chrome/install_static/test/scoped_install_details.h"
19 #include "chrome/installer/util/install_util.h"
20 #include "chrome/installer/util/util_constants.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using ::testing::Bool;
24 using ::testing::Combine;
25 using ::testing::Values;
26 using BeaconType = installer_util::Beacon::BeaconType;
27 using BeaconScope = installer_util::Beacon::BeaconScope;
28
29 namespace installer_util {
30
31 // A test fixture that exercises a beacon.
32 class BeaconTest : public ::testing::TestWithParam<
33 ::testing::tuple<BeaconType, BeaconScope, bool>> {
34 protected:
35 static const base::char16 kBeaconName[];
36
BeaconTest()37 BeaconTest()
38 : beacon_type_(::testing::get<0>(GetParam())),
39 beacon_scope_(::testing::get<1>(GetParam())),
40 system_install_(::testing::get<2>(GetParam())),
41 scoped_install_details_(system_install_),
42 beacon_(kBeaconName, beacon_type_, beacon_scope_) {}
43
SetUp()44 void SetUp() override {
45 // Override the registry so that tests can freely push state to it.
46 ASSERT_NO_FATAL_FAILURE(
47 registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
48 ASSERT_NO_FATAL_FAILURE(
49 registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
50 }
51
beacon_type() const52 BeaconType beacon_type() const { return beacon_type_; }
beacon_scope() const53 BeaconScope beacon_scope() const { return beacon_scope_; }
system_install() const54 bool system_install() const { return system_install_; }
beacon()55 Beacon* beacon() { return &beacon_; }
56
57 private:
58 BeaconType beacon_type_;
59 BeaconScope beacon_scope_;
60 bool system_install_;
61 install_static::ScopedInstallDetails scoped_install_details_;
62 Beacon beacon_;
63 registry_util::RegistryOverrideManager registry_override_manager_;
64 };
65
66 // static
67 const base::char16 BeaconTest::kBeaconName[] = L"TestBeacon";
68
69 // Nothing in the regsitry, so the beacon should not exist.
TEST_P(BeaconTest,GetNonExistent)70 TEST_P(BeaconTest, GetNonExistent) {
71 ASSERT_TRUE(beacon()->Get().is_null());
72 }
73
74 // Updating and then getting the beacon should return a value, and that it is
75 // within range.
TEST_P(BeaconTest,UpdateAndGet)76 TEST_P(BeaconTest, UpdateAndGet) {
77 base::Time before(base::Time::Now());
78 beacon()->Update();
79 base::Time after(base::Time::Now());
80 base::Time beacon_time(beacon()->Get());
81 ASSERT_FALSE(beacon_time.is_null());
82 ASSERT_LE(before, beacon_time);
83 ASSERT_GE(after, beacon_time);
84 }
85
86 // Tests that updating a first beacon only updates it the first time, but doing
87 // so for a last beacon always updates.
TEST_P(BeaconTest,UpdateTwice)88 TEST_P(BeaconTest, UpdateTwice) {
89 beacon()->Update();
90 base::Time beacon_time(beacon()->Get());
91
92 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
93
94 beacon()->Update();
95 if (beacon_type() == BeaconType::FIRST) {
96 ASSERT_EQ(beacon_time, beacon()->Get());
97 } else {
98 ASSERT_NE(beacon_time, beacon()->Get());
99 }
100 }
101
102 // Tests that the beacon is written into the proper location in the registry.
TEST_P(BeaconTest,Location)103 TEST_P(BeaconTest, Location) {
104 beacon()->Update();
105 const install_static::InstallDetails& install_details =
106 install_static::InstallDetails::Get();
107 HKEY right_root = system_install() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
108 HKEY wrong_root = system_install() ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
109 base::string16 right_key;
110 base::string16 wrong_key;
111 base::string16 value_name;
112
113 if (beacon_scope() == BeaconScope::PER_INSTALL || !system_install()) {
114 value_name = kBeaconName;
115 right_key = install_details.GetClientStateKeyPath();
116 wrong_key = install_details.GetClientStateMediumKeyPath();
117 } else {
118 ASSERT_TRUE(base::win::GetUserSidString(&value_name));
119 right_key =
120 install_details.GetClientStateMediumKeyPath() + L"\\" + kBeaconName;
121 wrong_key = install_details.GetClientStateKeyPath();
122 }
123
124 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
125 // Keys should not exist in the wrong root or in the right root but wrong key.
126 ASSERT_FALSE(
127 base::win::RegKey(wrong_root, right_key.c_str(), KEY_READ).Valid())
128 << right_key;
129 ASSERT_FALSE(
130 base::win::RegKey(wrong_root, wrong_key.c_str(), KEY_READ).Valid())
131 << wrong_key;
132 ASSERT_FALSE(
133 base::win::RegKey(right_root, wrong_key.c_str(), KEY_READ).Valid())
134 << wrong_key;
135 #else
136 // The tests above are skipped for Chromium builds because they fail for two
137 // reasons:
138 // - ClientState and ClientStateMedium are both Software\Chromium.
139 // - the registry override manager does its virtualization into
140 // Software\Chromium, so it always exists.
141
142 // Silence unused variable warnings.
143 ignore_result(wrong_root);
144 #endif
145
146 // The right key should exist.
147 base::win::RegKey key(right_root, right_key.c_str(), KEY_READ);
148 ASSERT_TRUE(key.Valid()) << right_key;
149 // And should have the value.
150 ASSERT_TRUE(key.HasValue(value_name.c_str())) << value_name;
151 }
152
153 // Run the tests for all combinations of beacon type, scope, and install level.
154 INSTANTIATE_TEST_SUITE_P(BeaconTest,
155 BeaconTest,
156 Combine(Values(BeaconType::FIRST, BeaconType::LAST),
157 Values(BeaconScope::PER_USER,
158 BeaconScope::PER_INSTALL),
159 Bool()));
160
161 class DefaultBrowserBeaconTest
162 : public ::testing::TestWithParam<
163 std::tuple<install_static::InstallConstantIndex, const char*>> {
164 protected:
165 using Super = ::testing::TestWithParam<
166 std::tuple<install_static::InstallConstantIndex, const char*>>;
167
SetUp()168 void SetUp() override {
169 Super::SetUp();
170
171 install_static::InstallConstantIndex mode_index;
172 const char* level;
173 std::tie(mode_index, level) = GetParam();
174
175 system_install_ = (std::string(level) != "user");
176
177 // Configure InstallDetails for the test.
178 scoped_install_details_ =
179 std::make_unique<install_static::ScopedInstallDetails>(system_install_,
180 mode_index);
181 // Override the registry so that tests can freely push state to it.
182 ASSERT_NO_FATAL_FAILURE(
183 registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
184 ASSERT_NO_FATAL_FAILURE(
185 registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
186 }
187
188 bool system_install_ = false;
189
190 private:
191 std::unique_ptr<install_static::ScopedInstallDetails> scoped_install_details_;
192 registry_util::RegistryOverrideManager registry_override_manager_;
193 };
194
195 // Tests that the default browser beacons work as expected.
TEST_P(DefaultBrowserBeaconTest,All)196 TEST_P(DefaultBrowserBeaconTest, All) {
197 std::unique_ptr<Beacon> last_was_default(MakeLastWasDefaultBeacon());
198 std::unique_ptr<Beacon> first_not_default(MakeFirstNotDefaultBeacon());
199
200 ASSERT_TRUE(last_was_default->Get().is_null());
201 ASSERT_TRUE(first_not_default->Get().is_null());
202
203 // Chrome is not default.
204 UpdateDefaultBrowserBeaconWithState(ShellUtil::NOT_DEFAULT);
205 ASSERT_TRUE(last_was_default->Get().is_null());
206 ASSERT_FALSE(first_not_default->Get().is_null());
207
208 // Then it is.
209 UpdateDefaultBrowserBeaconWithState(ShellUtil::IS_DEFAULT);
210 ASSERT_FALSE(last_was_default->Get().is_null());
211 ASSERT_TRUE(first_not_default->Get().is_null());
212
213 // It still is.
214 UpdateDefaultBrowserBeaconWithState(ShellUtil::IS_DEFAULT);
215 ASSERT_FALSE(last_was_default->Get().is_null());
216 ASSERT_TRUE(first_not_default->Get().is_null());
217
218 // Now it's not again.
219 UpdateDefaultBrowserBeaconWithState(ShellUtil::NOT_DEFAULT);
220 ASSERT_FALSE(last_was_default->Get().is_null());
221 ASSERT_FALSE(first_not_default->Get().is_null());
222
223 // And it still isn't.
224 UpdateDefaultBrowserBeaconWithState(ShellUtil::NOT_DEFAULT);
225 ASSERT_FALSE(last_was_default->Get().is_null());
226 ASSERT_FALSE(first_not_default->Get().is_null());
227 }
228
229 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
230 // Stable supports user and system levels.
231 INSTANTIATE_TEST_SUITE_P(
232 Stable,
233 DefaultBrowserBeaconTest,
234 testing::Combine(testing::Values(install_static::STABLE_INDEX),
235 testing::Values("user", "system")));
236 // Beta supports user and system levels.
237 INSTANTIATE_TEST_SUITE_P(
238 Beta,
239 DefaultBrowserBeaconTest,
240 testing::Combine(testing::Values(install_static::BETA_INDEX),
241 testing::Values("user", "system")));
242 // Dev supports user and system levels.
243 INSTANTIATE_TEST_SUITE_P(
244 Dev,
245 DefaultBrowserBeaconTest,
246 testing::Combine(testing::Values(install_static::DEV_INDEX),
247 testing::Values("user", "system")));
248 // Canary is only at user level.
249 INSTANTIATE_TEST_SUITE_P(
250 Canary,
251 DefaultBrowserBeaconTest,
252 testing::Combine(testing::Values(install_static::CANARY_INDEX),
253 testing::Values("user")));
254 #else // BUILDFLAG(GOOGLE_CHROME_BRANDING)
255 // Chromium supports user and system levels.
256 INSTANTIATE_TEST_SUITE_P(
257 Chromium,
258 DefaultBrowserBeaconTest,
259 testing::Combine(testing::Values(install_static::CHROMIUM_INDEX),
260 testing::Values("user", "system")));
261 #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
262
263 } // namespace installer_util
264