1 // Copyright (c) 2012 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/setup/installer_state.h"
6 
7 #include <windows.h>
8 
9 #include <stddef.h>
10 
11 #include <fstream>
12 
13 #include "base/base_paths.h"
14 #include "base/command_line.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/macros.h"
19 #include "base/path_service.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/scoped_path_override.h"
23 #include "base/test/test_reg_util_win.h"
24 #include "base/version.h"
25 #include "base/win/registry.h"
26 #include "base/win/scoped_handle.h"
27 #include "chrome/common/chrome_constants.h"
28 #include "chrome/install_static/install_util.h"
29 #include "chrome/installer/util/fake_installation_state.h"
30 #include "chrome/installer/util/fake_product_state.h"
31 #include "chrome/installer/util/google_update_constants.h"
32 #include "chrome/installer/util/initial_preferences.h"
33 #include "chrome/installer/util/installation_state.h"
34 #include "chrome/installer/util/installer_util_strings.h"
35 #include "chrome/installer/util/util_constants.h"
36 #include "chrome/installer/util/work_item.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38 
39 using base::win::RegKey;
40 using installer::InitialPreferences;
41 using installer::InstallationState;
42 using installer::InstallerState;
43 using registry_util::RegistryOverrideManager;
44 
45 class InstallerStateTest : public testing::Test {
46  protected:
InstallerStateTest()47   InstallerStateTest() {}
48 
SetUp()49   void SetUp() override { ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); }
50 
51   base::ScopedTempDir test_dir_;
52 
53  private:
54   DISALLOW_COPY_AND_ASSIGN(InstallerStateTest);
55 };
56 
57 // An installer state on which we can access otherwise protected members.
58 class MockInstallerState : public InstallerState {
59  public:
MockInstallerState()60   MockInstallerState() : InstallerState() {}
set_target_path(const base::FilePath & target_path)61   void set_target_path(const base::FilePath& target_path) {
62     target_path_ = target_path;
63   }
critical_update_version() const64   const base::Version& critical_update_version() const {
65     return critical_update_version_;
66   }
67 };
68 
TEST_F(InstallerStateTest,WithProduct)69 TEST_F(InstallerStateTest, WithProduct) {
70   const bool system_level = true;
71   base::CommandLine cmd_line = base::CommandLine::FromString(
72       std::wstring(L"setup.exe") + (system_level ? L" --system-level" : L""));
73   InitialPreferences prefs(cmd_line);
74   InstallationState machine_state;
75   machine_state.Initialize();
76   MockInstallerState installer_state;
77   installer_state.Initialize(cmd_line, prefs, machine_state);
78   installer_state.set_target_path(test_dir_.GetPath());
79   EXPECT_EQ(system_level, installer_state.system_install());
80 
81   const char kCurrentVersion[] = "1.2.3.4";
82   base::Version current_version(kCurrentVersion);
83 
84   HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
85   EXPECT_EQ(root, installer_state.root_key());
86 
87   {
88     RegistryOverrideManager override_manager;
89     ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
90     RegKey chrome_key(root, install_static::GetClientsKeyPath().c_str(),
91                       KEY_ALL_ACCESS);
92     EXPECT_TRUE(chrome_key.Valid());
93     if (chrome_key.Valid()) {
94       chrome_key.WriteValue(
95           google_update::kRegVersionField,
96           base::UTF8ToWide(current_version.GetString()).c_str());
97       machine_state.Initialize();
98       // TODO(tommi): Also test for when there exists a new_chrome.exe.
99       base::Version found_version(
100           installer_state.GetCurrentVersion(machine_state));
101       EXPECT_TRUE(found_version.IsValid());
102       if (found_version.IsValid())
103         EXPECT_EQ(current_version, found_version);
104     }
105   }
106 }
107 
TEST_F(InstallerStateTest,InstallerResult)108 TEST_F(InstallerStateTest, InstallerResult) {
109   const bool system_level = true;
110   HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
111 
112   RegKey key;
113   std::wstring launch_cmd = L"hey diddle diddle";
114   std::wstring value;
115   DWORD dw_value;
116 
117   // Check results for a fresh install of Chrome.
118   constexpr wchar_t command_line[] = L"setup.exe --system-level";
119 
120   RegistryOverrideManager override_manager;
121   ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
122   base::CommandLine cmd_line = base::CommandLine::FromString(command_line);
123   const InitialPreferences prefs(cmd_line);
124   InstallationState machine_state;
125   machine_state.Initialize();
126   InstallerState state;
127   state.Initialize(cmd_line, prefs, machine_state);
128   state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS,
129                              IDS_INSTALL_OS_ERROR_BASE, &launch_cmd);
130   EXPECT_EQ(ERROR_SUCCESS,
131             key.Open(root, install_static::GetClientStateKeyPath().c_str(),
132                      KEY_READ));
133   EXPECT_EQ(ERROR_SUCCESS,
134             key.ReadValueDW(installer::kInstallerResult, &dw_value));
135   EXPECT_EQ(static_cast<DWORD>(0), dw_value);
136   EXPECT_EQ(ERROR_SUCCESS,
137             key.ReadValueDW(installer::kInstallerError, &dw_value));
138   EXPECT_EQ(static_cast<DWORD>(installer::FIRST_INSTALL_SUCCESS), dw_value);
139   EXPECT_EQ(ERROR_SUCCESS,
140             key.ReadValue(installer::kInstallerResultUIString, &value));
141   EXPECT_FALSE(value.empty());
142   EXPECT_EQ(ERROR_SUCCESS,
143             key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value));
144   EXPECT_EQ(launch_cmd, value);
145 }
146 
TEST_F(InstallerStateTest,InitializeTwice)147 TEST_F(InstallerStateTest, InitializeTwice) {
148   // Override these paths so that they can be found after the registry override
149   // manager is in place.
150   base::FilePath temp;
151   base::PathService::Get(base::DIR_PROGRAM_FILES, &temp);
152   base::ScopedPathOverride program_files_override(base::DIR_PROGRAM_FILES,
153                                                   temp);
154   base::PathService::Get(base::DIR_PROGRAM_FILESX86, &temp);
155   base::ScopedPathOverride program_filesx86_override(base::DIR_PROGRAM_FILESX86,
156                                                      temp);
157   base::PathService::Get(base::DIR_LOCAL_APP_DATA, &temp);
158   base::ScopedPathOverride local_app_data_override(base::DIR_LOCAL_APP_DATA,
159                                                    temp);
160   registry_util::RegistryOverrideManager override_manager;
161   ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(HKEY_CURRENT_USER));
162   ASSERT_NO_FATAL_FAILURE(
163       override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE));
164 
165   InstallationState machine_state;
166   machine_state.Initialize();
167 
168   InstallerState installer_state;
169 
170   // Initialize the instance to install user-level Chrome.
171   {
172     base::CommandLine cmd_line(base::CommandLine::FromString(L"setup.exe"));
173     InitialPreferences prefs(cmd_line);
174     installer_state.Initialize(cmd_line, prefs, machine_state);
175   }
176   // Confirm the expected state.
177   EXPECT_EQ(InstallerState::USER_LEVEL, installer_state.level());
178   EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE,
179             installer_state.operation());
180   EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(),
181                      install_static::GetChromeInstallSubDirectory().c_str()));
182   EXPECT_FALSE(installer_state.verbose_logging());
183   EXPECT_EQ(installer_state.state_key(),
184             install_static::GetClientStateKeyPath());
185 
186   // Now initialize it to install system-level Chrome.
187   {
188     base::CommandLine cmd_line(base::CommandLine::FromString(
189         L"setup.exe --system-level --verbose-logging"));
190     InitialPreferences prefs(cmd_line);
191     installer_state.Initialize(cmd_line, prefs, machine_state);
192   }
193 
194   // Confirm that the old state is gone.
195   EXPECT_EQ(InstallerState::SYSTEM_LEVEL, installer_state.level());
196   EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE,
197             installer_state.operation());
198   EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(),
199                      install_static::GetChromeInstallSubDirectory().c_str()));
200   EXPECT_TRUE(installer_state.verbose_logging());
201   EXPECT_EQ(installer_state.state_key(),
202             install_static::GetClientStateKeyPath());
203 }
204 
205 // A fixture for testing InstallerState::DetermineCriticalVersion.  Individual
206 // tests must invoke Initialize() with a critical version.
207 class InstallerStateCriticalVersionTest : public ::testing::Test {
208  protected:
InstallerStateCriticalVersionTest()209   InstallerStateCriticalVersionTest()
210       : low_version_("15.0.874.106"),
211         opv_version_("15.0.874.255"),
212         middle_version_("16.0.912.32"),
213         pv_version_("16.0.912.255"),
214         high_version_("17.0.932.0"),
215         cmd_line_(base::CommandLine::NO_PROGRAM) {}
216 
217   // Initializes the InstallerState to use for a test run.  The returned
218   // instance's critical update version is set to |version|.  |version| may be
219   // nullptr, in which case the critical update version is unset.
Initialize(const base::Version & version)220   MockInstallerState& Initialize(const base::Version& version) {
221     cmd_line_ = !version.IsValid()
222                     ? base::CommandLine::FromString(L"setup.exe")
223                     : base::CommandLine::FromString(
224                           L"setup.exe --critical-update-version=" +
225                           base::ASCIIToUTF16(version.GetString()));
226     prefs_.reset(new InitialPreferences(cmd_line_));
227     machine_state_.Initialize();
228     installer_state_.Initialize(cmd_line_, *prefs_, machine_state_);
229     return installer_state_;
230   }
231 
232   const base::Version low_version_;
233   const base::Version opv_version_;
234   const base::Version middle_version_;
235   const base::Version pv_version_;
236   const base::Version high_version_;
237 
238   base::CommandLine cmd_line_;
239   std::unique_ptr<InitialPreferences> prefs_;
240   InstallationState machine_state_;
241   MockInstallerState installer_state_;
242 };
243 
244 // Test the case where the critical version is less than the currently-running
245 // Chrome.  The critical version is ignored since it doesn't apply.
TEST_F(InstallerStateCriticalVersionTest,CriticalBeforeOpv)246 TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) {
247   MockInstallerState& installer_state(Initialize(low_version_));
248 
249   EXPECT_EQ(installer_state.critical_update_version(), low_version_);
250   // Unable to determine the installed version, so assume critical update.
251   EXPECT_TRUE(
252       installer_state.DetermineCriticalVersion(base::Version(), pv_version_)
253           .IsValid());
254   // Installed version is past the critical update.
255   EXPECT_FALSE(
256       installer_state.DetermineCriticalVersion(opv_version_, pv_version_)
257           .IsValid());
258   // Installed version is past the critical update.
259   EXPECT_FALSE(
260       installer_state.DetermineCriticalVersion(pv_version_, pv_version_)
261           .IsValid());
262 }
263 
264 // Test the case where the critical version is equal to the currently-running
265 // Chrome.  The critical version is ignored since it doesn't apply.
TEST_F(InstallerStateCriticalVersionTest,CriticalEqualsOpv)266 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) {
267   MockInstallerState& installer_state(Initialize(opv_version_));
268 
269   EXPECT_EQ(installer_state.critical_update_version(), opv_version_);
270   // Unable to determine the installed version, so assume critical update.
271   EXPECT_TRUE(
272       installer_state.DetermineCriticalVersion(base::Version(), pv_version_)
273           .IsValid());
274   // Installed version equals the critical update.
275   EXPECT_FALSE(
276       installer_state.DetermineCriticalVersion(opv_version_, pv_version_)
277           .IsValid());
278   // Installed version equals the critical update.
279   EXPECT_FALSE(
280       installer_state.DetermineCriticalVersion(pv_version_, pv_version_)
281           .IsValid());
282 }
283 
284 // Test the case where the critical version is between the currently-running
285 // Chrome and the to-be-installed Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalBetweenOpvAndPv)286 TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) {
287   MockInstallerState& installer_state(Initialize(middle_version_));
288 
289   EXPECT_EQ(installer_state.critical_update_version(), middle_version_);
290   // Unable to determine the installed version, so assume critical update.
291   EXPECT_TRUE(
292       installer_state.DetermineCriticalVersion(base::Version(), pv_version_)
293           .IsValid());
294   // Installed version before the critical update.
295   EXPECT_TRUE(
296       installer_state.DetermineCriticalVersion(opv_version_, pv_version_)
297           .IsValid());
298   // Installed version is past the critical update.
299   EXPECT_FALSE(
300       installer_state.DetermineCriticalVersion(pv_version_, pv_version_)
301           .IsValid());
302 }
303 
304 // Test the case where the critical version is the same as the to-be-installed
305 // Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalEqualsPv)306 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) {
307   MockInstallerState& installer_state(Initialize(pv_version_));
308 
309   EXPECT_EQ(installer_state.critical_update_version(), pv_version_);
310   // Unable to determine the installed version, so assume critical update.
311   EXPECT_TRUE(
312       installer_state.DetermineCriticalVersion(base::Version(), pv_version_)
313           .IsValid());
314   // Installed version before the critical update.
315   EXPECT_TRUE(
316       installer_state.DetermineCriticalVersion(opv_version_, pv_version_)
317           .IsValid());
318   // Installed version equals the critical update.
319   EXPECT_FALSE(
320       installer_state.DetermineCriticalVersion(pv_version_, pv_version_)
321           .IsValid());
322 }
323 
324 // Test the case where the critical version is greater than the to-be-installed
325 // Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalAfterPv)326 TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) {
327   MockInstallerState& installer_state(Initialize(high_version_));
328 
329   EXPECT_EQ(installer_state.critical_update_version(), high_version_);
330   // Critical update newer than the new version.
331   EXPECT_FALSE(
332       installer_state.DetermineCriticalVersion(base::Version(), pv_version_)
333           .IsValid());
334   EXPECT_FALSE(
335       installer_state.DetermineCriticalVersion(opv_version_, pv_version_)
336           .IsValid());
337   EXPECT_FALSE(
338       installer_state.DetermineCriticalVersion(pv_version_, pv_version_)
339           .IsValid());
340 }
341