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 <windows.h>
6
7 #include <fstream>
8
9 #include "base/base_paths.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/test/test_reg_util_win.h"
19 #include "base/version.h"
20 #include "base/win/registry.h"
21 #include "base/win/scoped_handle.h"
22 #include "chrome/common/chrome_constants.h"
23 #include "chrome/installer/test/alternate_version_generator.h"
24 #include "chrome/installer/util/fake_installation_state.h"
25 #include "chrome/installer/util/fake_product_state.h"
26 #include "chrome/installer/util/google_update_constants.h"
27 #include "chrome/installer/util/helper.h"
28 #include "chrome/installer/util/installation_state.h"
29 #include "chrome/installer/util/installer_state.h"
30 #include "chrome/installer/util/master_preferences.h"
31 #include "chrome/installer/util/product_unittest.h"
32 #include "chrome/installer/util/util_constants.h"
33 #include "chrome/installer/util/work_item.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35
36 #include "installer_util_strings.h" // NOLINT
37
38 using base::win::RegKey;
39 using installer::InstallationState;
40 using installer::InstallerState;
41 using installer::MasterPreferences;
42 using registry_util::RegistryOverrideManager;
43
44 class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys {
45 protected:
46 };
47
48 // An installer state on which we can access otherwise protected members.
49 class MockInstallerState : public InstallerState {
50 public:
MockInstallerState()51 MockInstallerState() : InstallerState() { }
set_target_path(const base::FilePath & target_path)52 void set_target_path(const base::FilePath& target_path) {
53 target_path_ = target_path;
54 }
IsFileInUse(const base::FilePath & file)55 static bool IsFileInUse(const base::FilePath& file) {
56 return InstallerState::IsFileInUse(file);
57 }
critical_update_version() const58 const Version& critical_update_version() const {
59 return critical_update_version_;
60 }
GetExistingExeVersions(std::set<std::string> * existing_version_strings)61 void GetExistingExeVersions(std::set<std::string>* existing_version_strings) {
62 return InstallerState::GetExistingExeVersions(existing_version_strings);
63 }
64 };
65
66 // Simple function to dump some text into a new file.
CreateTextFile(const std::wstring & filename,const std::wstring & contents)67 void CreateTextFile(const std::wstring& filename,
68 const std::wstring& contents) {
69 std::ofstream file;
70 file.open(filename.c_str());
71 ASSERT_TRUE(file.is_open());
72 file << contents;
73 file.close();
74 }
75
BuildSingleChromeState(const base::FilePath & target_dir,MockInstallerState * installer_state)76 void BuildSingleChromeState(const base::FilePath& target_dir,
77 MockInstallerState* installer_state) {
78 CommandLine cmd_line = CommandLine::FromString(L"setup.exe");
79 MasterPreferences prefs(cmd_line);
80 InstallationState machine_state;
81 machine_state.Initialize();
82 installer_state->Initialize(cmd_line, prefs, machine_state);
83 installer_state->set_target_path(target_dir);
84 EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER)
85 != NULL);
86 }
87
88 wchar_t text_content_1[] = L"delete me";
89 wchar_t text_content_2[] = L"delete me as well";
90
91 // Delete version directories. Everything lower than the given version
92 // should be deleted.
TEST_F(InstallerStateTest,Delete)93 TEST_F(InstallerStateTest, Delete) {
94 // TODO(grt): move common stuff into the test fixture.
95 // Create a Chrome dir
96 base::FilePath chrome_dir(test_dir_.path());
97 chrome_dir = chrome_dir.AppendASCII("chrome");
98 base::CreateDirectory(chrome_dir);
99 ASSERT_TRUE(base::PathExists(chrome_dir));
100
101 base::FilePath chrome_dir_1(chrome_dir);
102 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
103 base::CreateDirectory(chrome_dir_1);
104 ASSERT_TRUE(base::PathExists(chrome_dir_1));
105
106 base::FilePath chrome_dir_2(chrome_dir);
107 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
108 base::CreateDirectory(chrome_dir_2);
109 ASSERT_TRUE(base::PathExists(chrome_dir_2));
110
111 base::FilePath chrome_dir_3(chrome_dir);
112 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
113 base::CreateDirectory(chrome_dir_3);
114 ASSERT_TRUE(base::PathExists(chrome_dir_3));
115
116 base::FilePath chrome_dir_4(chrome_dir);
117 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
118 base::CreateDirectory(chrome_dir_4);
119 ASSERT_TRUE(base::PathExists(chrome_dir_4));
120
121 base::FilePath chrome_dll_1(chrome_dir_1);
122 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
123 CreateTextFile(chrome_dll_1.value(), text_content_1);
124 ASSERT_TRUE(base::PathExists(chrome_dll_1));
125
126 base::FilePath chrome_dll_2(chrome_dir_2);
127 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
128 CreateTextFile(chrome_dll_2.value(), text_content_1);
129 ASSERT_TRUE(base::PathExists(chrome_dll_2));
130
131 base::FilePath chrome_dll_3(chrome_dir_3);
132 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
133 CreateTextFile(chrome_dll_3.value(), text_content_1);
134 ASSERT_TRUE(base::PathExists(chrome_dll_3));
135
136 base::FilePath chrome_dll_4(chrome_dir_4);
137 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
138 CreateTextFile(chrome_dll_4.value(), text_content_1);
139 ASSERT_TRUE(base::PathExists(chrome_dll_4));
140
141 MockInstallerState installer_state;
142 BuildSingleChromeState(chrome_dir, &installer_state);
143 Version latest_version("1.0.4.0");
144 {
145 base::ScopedTempDir temp_dir;
146 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
147 installer_state.RemoveOldVersionDirectories(latest_version, NULL,
148 temp_dir.path());
149 }
150
151 // old versions should be gone
152 EXPECT_FALSE(base::PathExists(chrome_dir_1));
153 EXPECT_FALSE(base::PathExists(chrome_dir_2));
154 EXPECT_FALSE(base::PathExists(chrome_dir_3));
155 // the latest version should stay
156 EXPECT_TRUE(base::PathExists(chrome_dll_4));
157 }
158
159 // Delete older version directories, keeping the one in used intact.
TEST_F(InstallerStateTest,DeleteInUsed)160 TEST_F(InstallerStateTest, DeleteInUsed) {
161 // Create a Chrome dir
162 base::FilePath chrome_dir(test_dir_.path());
163 chrome_dir = chrome_dir.AppendASCII("chrome");
164 base::CreateDirectory(chrome_dir);
165 ASSERT_TRUE(base::PathExists(chrome_dir));
166
167 base::FilePath chrome_dir_1(chrome_dir);
168 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
169 base::CreateDirectory(chrome_dir_1);
170 ASSERT_TRUE(base::PathExists(chrome_dir_1));
171
172 base::FilePath chrome_dir_2(chrome_dir);
173 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
174 base::CreateDirectory(chrome_dir_2);
175 ASSERT_TRUE(base::PathExists(chrome_dir_2));
176
177 base::FilePath chrome_dir_3(chrome_dir);
178 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
179 base::CreateDirectory(chrome_dir_3);
180 ASSERT_TRUE(base::PathExists(chrome_dir_3));
181
182 base::FilePath chrome_dir_4(chrome_dir);
183 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
184 base::CreateDirectory(chrome_dir_4);
185 ASSERT_TRUE(base::PathExists(chrome_dir_4));
186
187 base::FilePath chrome_dll_1(chrome_dir_1);
188 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
189 CreateTextFile(chrome_dll_1.value(), text_content_1);
190 ASSERT_TRUE(base::PathExists(chrome_dll_1));
191
192 base::FilePath chrome_dll_2(chrome_dir_2);
193 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
194 CreateTextFile(chrome_dll_2.value(), text_content_1);
195 ASSERT_TRUE(base::PathExists(chrome_dll_2));
196
197 // Open the file to make it in use.
198 std::ofstream file;
199 file.open(chrome_dll_2.value().c_str());
200
201 base::FilePath chrome_othera_2(chrome_dir_2);
202 chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll");
203 CreateTextFile(chrome_othera_2.value(), text_content_2);
204 ASSERT_TRUE(base::PathExists(chrome_othera_2));
205
206 base::FilePath chrome_otherb_2(chrome_dir_2);
207 chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll");
208 CreateTextFile(chrome_otherb_2.value(), text_content_2);
209 ASSERT_TRUE(base::PathExists(chrome_otherb_2));
210
211 base::FilePath chrome_dll_3(chrome_dir_3);
212 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
213 CreateTextFile(chrome_dll_3.value(), text_content_1);
214 ASSERT_TRUE(base::PathExists(chrome_dll_3));
215
216 base::FilePath chrome_dll_4(chrome_dir_4);
217 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
218 CreateTextFile(chrome_dll_4.value(), text_content_1);
219 ASSERT_TRUE(base::PathExists(chrome_dll_4));
220
221 MockInstallerState installer_state;
222 BuildSingleChromeState(chrome_dir, &installer_state);
223 Version latest_version("1.0.4.0");
224 Version existing_version("1.0.1.0");
225 {
226 base::ScopedTempDir temp_dir;
227 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
228 installer_state.RemoveOldVersionDirectories(latest_version,
229 &existing_version,
230 temp_dir.path());
231 }
232
233 // the version defined as the existing version should stay
234 EXPECT_TRUE(base::PathExists(chrome_dir_1));
235 // old versions not in used should be gone
236 EXPECT_FALSE(base::PathExists(chrome_dir_3));
237 // every thing under in used version should stay
238 EXPECT_TRUE(base::PathExists(chrome_dir_2));
239 EXPECT_TRUE(base::PathExists(chrome_dll_2));
240 EXPECT_TRUE(base::PathExists(chrome_othera_2));
241 EXPECT_TRUE(base::PathExists(chrome_otherb_2));
242 // the latest version should stay
243 EXPECT_TRUE(base::PathExists(chrome_dll_4));
244 }
245
246 // Tests a few basic things of the Package class. Makes sure that the path
247 // operations are correct
TEST_F(InstallerStateTest,Basic)248 TEST_F(InstallerStateTest, Basic) {
249 const bool multi_install = false;
250 const bool system_level = true;
251 CommandLine cmd_line = CommandLine::FromString(
252 std::wstring(L"setup.exe") +
253 (multi_install ? L" --multi-install --chrome" : L"") +
254 (system_level ? L" --system-level" : L""));
255 MasterPreferences prefs(cmd_line);
256 InstallationState machine_state;
257 machine_state.Initialize();
258 MockInstallerState installer_state;
259 installer_state.Initialize(cmd_line, prefs, machine_state);
260 installer_state.set_target_path(test_dir_.path());
261 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value());
262 EXPECT_EQ(1U, installer_state.products().size());
263
264 const char kOldVersion[] = "1.2.3.4";
265 const char kNewVersion[] = "2.3.4.5";
266
267 Version new_version(kNewVersion);
268 Version old_version(kOldVersion);
269 ASSERT_TRUE(new_version.IsValid());
270 ASSERT_TRUE(old_version.IsValid());
271
272 base::FilePath installer_dir(
273 installer_state.GetInstallerDirectory(new_version));
274 EXPECT_FALSE(installer_dir.empty());
275
276 base::FilePath new_version_dir(installer_state.target_path().Append(
277 base::UTF8ToWide(new_version.GetString())));
278 base::FilePath old_version_dir(installer_state.target_path().Append(
279 base::UTF8ToWide(old_version.GetString())));
280
281 EXPECT_FALSE(base::PathExists(new_version_dir));
282 EXPECT_FALSE(base::PathExists(old_version_dir));
283
284 EXPECT_FALSE(base::PathExists(installer_dir));
285 base::CreateDirectory(installer_dir);
286 EXPECT_TRUE(base::PathExists(new_version_dir));
287
288 base::CreateDirectory(old_version_dir);
289 EXPECT_TRUE(base::PathExists(old_version_dir));
290
291 // Create a fake chrome.dll key file in the old version directory. This
292 // should prevent the old version directory from getting deleted.
293 base::FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll));
294 EXPECT_FALSE(base::PathExists(old_chrome_dll));
295
296 // Hold on to the file exclusively to prevent the directory from
297 // being deleted.
298 base::win::ScopedHandle file(
299 ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ,
300 0, NULL, OPEN_ALWAYS, 0, NULL));
301 EXPECT_TRUE(file.IsValid());
302 EXPECT_TRUE(base::PathExists(old_chrome_dll));
303
304 base::ScopedTempDir temp_dir;
305 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
306
307 // Don't explicitly tell the directory cleanup logic not to delete the
308 // old version, rely on the key files to keep it around.
309 installer_state.RemoveOldVersionDirectories(new_version,
310 NULL,
311 temp_dir.path());
312
313 // The old directory should still exist.
314 EXPECT_TRUE(base::PathExists(old_version_dir));
315 EXPECT_TRUE(base::PathExists(new_version_dir));
316
317 // Now close the file handle to make it possible to delete our key file.
318 file.Close();
319
320 installer_state.RemoveOldVersionDirectories(new_version,
321 NULL,
322 temp_dir.path());
323 // The new directory should still exist.
324 EXPECT_TRUE(base::PathExists(new_version_dir));
325
326 // Now, the old directory and key file should be gone.
327 EXPECT_FALSE(base::PathExists(old_chrome_dll));
328 EXPECT_FALSE(base::PathExists(old_version_dir));
329 }
330
TEST_F(InstallerStateTest,WithProduct)331 TEST_F(InstallerStateTest, WithProduct) {
332 const bool multi_install = false;
333 const bool system_level = true;
334 CommandLine cmd_line = CommandLine::FromString(
335 std::wstring(L"setup.exe") +
336 (multi_install ? L" --multi-install --chrome" : L"") +
337 (system_level ? L" --system-level" : L""));
338 MasterPreferences prefs(cmd_line);
339 InstallationState machine_state;
340 machine_state.Initialize();
341 MockInstallerState installer_state;
342 installer_state.Initialize(cmd_line, prefs, machine_state);
343 installer_state.set_target_path(test_dir_.path());
344 EXPECT_EQ(1U, installer_state.products().size());
345 EXPECT_EQ(system_level, installer_state.system_install());
346
347 const char kCurrentVersion[] = "1.2.3.4";
348 Version current_version(kCurrentVersion);
349
350 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
351 EXPECT_EQ(root, installer_state.root_key());
352
353 {
354 RegistryOverrideManager override_manager;
355 override_manager.OverrideRegistry(root, L"root_pit");
356 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
357 BrowserDistribution::CHROME_BROWSER);
358 RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS);
359 EXPECT_TRUE(chrome_key.Valid());
360 if (chrome_key.Valid()) {
361 chrome_key.WriteValue(google_update::kRegVersionField,
362 base::UTF8ToWide(
363 current_version.GetString()).c_str());
364 machine_state.Initialize();
365 // TODO(tommi): Also test for when there exists a new_chrome.exe.
366 Version found_version(*installer_state.GetCurrentVersion(machine_state));
367 EXPECT_TRUE(found_version.IsValid());
368 if (found_version.IsValid())
369 EXPECT_TRUE(current_version.Equals(found_version));
370 }
371 }
372 }
373
TEST_F(InstallerStateTest,InstallerResult)374 TEST_F(InstallerStateTest, InstallerResult) {
375 const bool system_level = true;
376 bool multi_install = false;
377 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
378
379 RegKey key;
380 std::wstring launch_cmd = L"hey diddle diddle";
381 std::wstring value;
382 DWORD dw_value;
383
384 // check results for a fresh install of single Chrome
385 {
386 RegistryOverrideManager override_manager;
387 override_manager.OverrideRegistry(root, L"root_inst_res");
388 CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level");
389 const MasterPreferences prefs(cmd_line);
390 InstallationState machine_state;
391 machine_state.Initialize();
392 InstallerState state;
393 state.Initialize(cmd_line, prefs, machine_state);
394 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS,
395 IDS_INSTALL_OS_ERROR_BASE, &launch_cmd);
396 BrowserDistribution* distribution =
397 BrowserDistribution::GetSpecificDistribution(
398 BrowserDistribution::CHROME_BROWSER);
399 EXPECT_EQ(ERROR_SUCCESS,
400 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
401 EXPECT_EQ(ERROR_SUCCESS,
402 key.ReadValueDW(installer::kInstallerResult, &dw_value));
403 EXPECT_EQ(static_cast<DWORD>(0), dw_value);
404 EXPECT_EQ(ERROR_SUCCESS,
405 key.ReadValueDW(installer::kInstallerError, &dw_value));
406 EXPECT_EQ(static_cast<DWORD>(installer::FIRST_INSTALL_SUCCESS), dw_value);
407 EXPECT_EQ(ERROR_SUCCESS,
408 key.ReadValue(installer::kInstallerResultUIString, &value));
409 EXPECT_FALSE(value.empty());
410 EXPECT_EQ(ERROR_SUCCESS,
411 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value));
412 EXPECT_EQ(launch_cmd, value);
413 }
414
415 // check results for a fresh install of multi Chrome
416 {
417 RegistryOverrideManager override_manager;
418 override_manager.OverrideRegistry(root, L"root_inst_res");
419 CommandLine cmd_line = CommandLine::FromString(
420 L"setup.exe --system-level --multi-install --chrome");
421 const MasterPreferences prefs(cmd_line);
422 InstallationState machine_state;
423 machine_state.Initialize();
424 InstallerState state;
425 state.Initialize(cmd_line, prefs, machine_state);
426 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0,
427 &launch_cmd);
428 BrowserDistribution* distribution =
429 BrowserDistribution::GetSpecificDistribution(
430 BrowserDistribution::CHROME_BROWSER);
431 BrowserDistribution* binaries =
432 BrowserDistribution::GetSpecificDistribution(
433 BrowserDistribution::CHROME_BINARIES);
434 EXPECT_EQ(ERROR_SUCCESS,
435 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
436 EXPECT_EQ(ERROR_SUCCESS,
437 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value));
438 EXPECT_EQ(launch_cmd, value);
439 EXPECT_EQ(ERROR_SUCCESS,
440 key.Open(root, binaries->GetStateKey().c_str(), KEY_READ));
441 EXPECT_EQ(ERROR_SUCCESS,
442 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value));
443 EXPECT_EQ(launch_cmd, value);
444 key.Close();
445 }
446 }
447
448 // Test GetCurrentVersion when migrating single Chrome to multi
TEST_F(InstallerStateTest,GetCurrentVersionMigrateChrome)449 TEST_F(InstallerStateTest, GetCurrentVersionMigrateChrome) {
450 using installer::FakeInstallationState;
451
452 const bool system_install = false;
453 FakeInstallationState machine_state;
454
455 // Pretend that this version of single-install Chrome is already installed.
456 machine_state.AddChrome(system_install, false,
457 new Version(chrome::kChromeVersion));
458
459 // Now we're invoked to install multi Chrome.
460 CommandLine cmd_line(
461 CommandLine::FromString(L"setup.exe --multi-install --chrome"));
462 MasterPreferences prefs(cmd_line);
463 InstallerState installer_state;
464 installer_state.Initialize(cmd_line, prefs, machine_state);
465
466 // Is the Chrome version picked up?
467 scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state));
468 EXPECT_TRUE(version.get() != NULL);
469 }
470
TEST_F(InstallerStateTest,IsFileInUse)471 TEST_F(InstallerStateTest, IsFileInUse) {
472 base::ScopedTempDir temp_dir;
473 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
474
475 base::FilePath temp_file;
476 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file));
477
478 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file));
479
480 {
481 // Open a handle to the file with the same access mode and sharing options
482 // as the loader.
483 base::win::ScopedHandle temp_handle(
484 CreateFile(temp_file.value().c_str(),
485 SYNCHRONIZE | FILE_EXECUTE,
486 FILE_SHARE_DELETE | FILE_SHARE_READ,
487 NULL, OPEN_EXISTING, 0, 0));
488 ASSERT_TRUE(temp_handle != NULL);
489
490 // The file should now be in use.
491 EXPECT_TRUE(MockInstallerState::IsFileInUse(temp_file));
492 }
493
494 // And once the handle is gone, it should no longer be in use.
495 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file));
496 }
497
TEST_F(InstallerStateTest,RemoveOldVersionDirs)498 TEST_F(InstallerStateTest, RemoveOldVersionDirs) {
499 MockInstallerState installer_state;
500 installer_state.set_target_path(test_dir_.path());
501 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value());
502
503 const char kOldVersion[] = "2.0.0.0";
504 const char kNewVersion[] = "3.0.0.0";
505 const char kOldChromeExeVersion[] = "2.1.0.0";
506 const char kChromeExeVersion[] = "2.1.1.1";
507 const char kNewChromeExeVersion[] = "3.0.0.0";
508
509 Version new_version(kNewVersion);
510 Version old_version(kOldVersion);
511 Version old_chrome_exe_version(kOldChromeExeVersion);
512 Version chrome_exe_version(kChromeExeVersion);
513 Version new_chrome_exe_version(kNewChromeExeVersion);
514
515 ASSERT_TRUE(new_version.IsValid());
516 ASSERT_TRUE(old_version.IsValid());
517 ASSERT_TRUE(old_chrome_exe_version.IsValid());
518 ASSERT_TRUE(chrome_exe_version.IsValid());
519 ASSERT_TRUE(new_chrome_exe_version.IsValid());
520
521 // Set up a bunch of version dir paths.
522 base::FilePath version_dirs[] = {
523 installer_state.target_path().Append(L"1.2.3.4"),
524 installer_state.target_path().Append(L"1.2.3.5"),
525 installer_state.target_path().Append(L"1.2.3.6"),
526 installer_state.target_path().Append(base::ASCIIToWide(kOldVersion)),
527 installer_state.target_path().Append(
528 base::ASCIIToWide(kOldChromeExeVersion)),
529 installer_state.target_path().Append(L"2.1.1.0"),
530 installer_state.target_path().Append(base::ASCIIToWide(kChromeExeVersion)),
531 installer_state.target_path().Append(base::ASCIIToWide(kNewVersion)),
532 installer_state.target_path().Append(L"3.9.1.1"),
533 };
534
535 // Create the version directories.
536 for (int i = 0; i < arraysize(version_dirs); i++) {
537 base::CreateDirectory(version_dirs[i]);
538 EXPECT_TRUE(base::PathExists(version_dirs[i]));
539 }
540
541 // Create exes with the appropriate version resource.
542 // Use the current test exe as a baseline.
543 base::FilePath exe_path;
544 ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe_path));
545
546 struct target_info {
547 base::FilePath target_file;
548 const Version& target_version;
549 } targets[] = {
550 { installer_state.target_path().Append(installer::kChromeOldExe),
551 old_chrome_exe_version },
552 { installer_state.target_path().Append(installer::kChromeExe),
553 chrome_exe_version },
554 { installer_state.target_path().Append(installer::kChromeNewExe),
555 new_chrome_exe_version },
556 };
557 for (int i = 0; i < arraysize(targets); ++i) {
558 ASSERT_TRUE(upgrade_test::GenerateSpecificPEFileVersion(
559 exe_path, targets[i].target_file, targets[i].target_version));
560 }
561
562 // Call GetExistingExeVersions, validate that picks up the
563 // exe resources.
564 std::set<std::string> expected_exe_versions;
565 expected_exe_versions.insert(kOldChromeExeVersion);
566 expected_exe_versions.insert(kChromeExeVersion);
567 expected_exe_versions.insert(kNewChromeExeVersion);
568
569 std::set<std::string> actual_exe_versions;
570 installer_state.GetExistingExeVersions(&actual_exe_versions);
571 EXPECT_EQ(expected_exe_versions, actual_exe_versions);
572
573 // Call RemoveOldVersionDirectories
574 installer_state.RemoveOldVersionDirectories(new_version,
575 &old_version,
576 installer_state.target_path());
577
578 // What we expect to have left.
579 std::set<std::string> expected_remaining_dirs;
580 expected_remaining_dirs.insert(kOldVersion);
581 expected_remaining_dirs.insert(kNewVersion);
582 expected_remaining_dirs.insert(kOldChromeExeVersion);
583 expected_remaining_dirs.insert(kChromeExeVersion);
584 expected_remaining_dirs.insert(kNewChromeExeVersion);
585
586 // Enumerate dirs in target_path(), ensure only desired remain.
587 base::FileEnumerator version_enum(installer_state.target_path(), false,
588 base::FileEnumerator::DIRECTORIES);
589 for (base::FilePath next_version = version_enum.Next(); !next_version.empty();
590 next_version = version_enum.Next()) {
591 base::FilePath dir_name(next_version.BaseName());
592 Version version(base::UTF16ToASCII(dir_name.value()));
593 if (version.IsValid()) {
594 EXPECT_TRUE(expected_remaining_dirs.erase(version.GetString()))
595 << "Unexpected version dir found: " << version.GetString();
596 }
597 }
598
599 std::set<std::string>::const_iterator iter(
600 expected_remaining_dirs.begin());
601 for (; iter != expected_remaining_dirs.end(); ++iter)
602 ADD_FAILURE() << "Expected to find version dir for " << *iter;
603 }
604
TEST_F(InstallerStateTest,InitializeTwice)605 TEST_F(InstallerStateTest, InitializeTwice) {
606 InstallationState machine_state;
607 machine_state.Initialize();
608
609 InstallerState installer_state;
610
611 // Initialize the instance to install multi Chrome.
612 {
613 CommandLine cmd_line(
614 CommandLine::FromString(L"setup.exe --multi-install --chrome"));
615 MasterPreferences prefs(cmd_line);
616 installer_state.Initialize(cmd_line, prefs, machine_state);
617 }
618 // Confirm the expected state.
619 EXPECT_EQ(InstallerState::USER_LEVEL, installer_state.level());
620 EXPECT_EQ(InstallerState::MULTI_PACKAGE, installer_state.package_type());
621 EXPECT_EQ(InstallerState::MULTI_INSTALL, installer_state.operation());
622 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(),
623 BrowserDistribution::GetSpecificDistribution(
624 BrowserDistribution::CHROME_BINARIES)->
625 GetInstallSubDir().c_str()));
626 EXPECT_FALSE(installer_state.verbose_logging());
627 EXPECT_EQ(installer_state.state_key(),
628 BrowserDistribution::GetSpecificDistribution(
629 BrowserDistribution::CHROME_BROWSER)->GetStateKey());
630 EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER);
631 EXPECT_TRUE(installer_state.multi_package_binaries_distribution());
632 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER));
633
634 // Now initialize it to install system-level single Chrome.
635 {
636 CommandLine cmd_line(
637 CommandLine::FromString(L"setup.exe --system-level --verbose-logging"));
638 MasterPreferences prefs(cmd_line);
639 installer_state.Initialize(cmd_line, prefs, machine_state);
640 }
641
642 // Confirm that the old state is gone.
643 EXPECT_EQ(InstallerState::SYSTEM_LEVEL, installer_state.level());
644 EXPECT_EQ(InstallerState::SINGLE_PACKAGE, installer_state.package_type());
645 EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE,
646 installer_state.operation());
647 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(),
648 BrowserDistribution::GetSpecificDistribution(
649 BrowserDistribution::CHROME_BROWSER)->
650 GetInstallSubDir().c_str()));
651 EXPECT_TRUE(installer_state.verbose_logging());
652 EXPECT_EQ(installer_state.state_key(),
653 BrowserDistribution::GetSpecificDistribution(
654 BrowserDistribution::CHROME_BROWSER)->GetStateKey());
655 EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER);
656 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER));
657 }
658
659 // A fixture for testing InstallerState::DetermineCriticalVersion. Individual
660 // tests must invoke Initialize() with a critical version.
661 class InstallerStateCriticalVersionTest : public ::testing::Test {
662 protected:
InstallerStateCriticalVersionTest()663 InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {}
664
665 // Creates a set of versions for use by all test runs.
SetUpTestCase()666 static void SetUpTestCase() {
667 low_version_ = new Version("15.0.874.106");
668 opv_version_ = new Version("15.0.874.255");
669 middle_version_ = new Version("16.0.912.32");
670 pv_version_ = new Version("16.0.912.255");
671 high_version_ = new Version("17.0.932.0");
672 }
673
674 // Cleans up versions used by all test runs.
TearDownTestCase()675 static void TearDownTestCase() {
676 delete low_version_;
677 delete opv_version_;
678 delete middle_version_;
679 delete pv_version_;
680 delete high_version_;
681 }
682
683 // Initializes the InstallerState to use for a test run. The returned
684 // instance's critical update version is set to |version|. |version| may be
685 // NULL, in which case the critical update version is unset.
Initialize(const Version * version)686 MockInstallerState& Initialize(const Version* version) {
687 cmd_line_ = version == NULL ?
688 CommandLine::FromString(L"setup.exe") :
689 CommandLine::FromString(
690 L"setup.exe --critical-update-version=" +
691 base::ASCIIToWide(version->GetString()));
692 prefs_.reset(new MasterPreferences(cmd_line_));
693 machine_state_.Initialize();
694 installer_state_.Initialize(cmd_line_, *prefs_, machine_state_);
695 return installer_state_;
696 }
697
698 static Version* low_version_;
699 static Version* opv_version_;
700 static Version* middle_version_;
701 static Version* pv_version_;
702 static Version* high_version_;
703
704 CommandLine cmd_line_;
705 scoped_ptr<MasterPreferences> prefs_;
706 InstallationState machine_state_;
707 MockInstallerState installer_state_;
708 };
709
710 Version* InstallerStateCriticalVersionTest::low_version_ = NULL;
711 Version* InstallerStateCriticalVersionTest::opv_version_ = NULL;
712 Version* InstallerStateCriticalVersionTest::middle_version_ = NULL;
713 Version* InstallerStateCriticalVersionTest::pv_version_ = NULL;
714 Version* InstallerStateCriticalVersionTest::high_version_ = NULL;
715
716 // Test the case where the critical version is less than the currently-running
717 // Chrome. The critical version is ignored since it doesn't apply.
TEST_F(InstallerStateCriticalVersionTest,CriticalBeforeOpv)718 TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) {
719 MockInstallerState& installer_state(Initialize(low_version_));
720
721 EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_));
722 // Unable to determine the installed version, so assume critical update.
723 EXPECT_TRUE(
724 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
725 // Installed version is past the critical update.
726 EXPECT_FALSE(
727 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
728 .IsValid());
729 // Installed version is past the critical update.
730 EXPECT_FALSE(
731 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
732 .IsValid());
733 }
734
735 // Test the case where the critical version is equal to the currently-running
736 // Chrome. The critical version is ignored since it doesn't apply.
TEST_F(InstallerStateCriticalVersionTest,CriticalEqualsOpv)737 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) {
738 MockInstallerState& installer_state(Initialize(opv_version_));
739
740 EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_));
741 // Unable to determine the installed version, so assume critical update.
742 EXPECT_TRUE(
743 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
744 // Installed version equals the critical update.
745 EXPECT_FALSE(
746 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
747 .IsValid());
748 // Installed version equals the critical update.
749 EXPECT_FALSE(
750 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
751 .IsValid());
752 }
753
754 // Test the case where the critical version is between the currently-running
755 // Chrome and the to-be-installed Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalBetweenOpvAndPv)756 TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) {
757 MockInstallerState& installer_state(Initialize(middle_version_));
758
759 EXPECT_TRUE(installer_state.critical_update_version().Equals(
760 *middle_version_));
761 // Unable to determine the installed version, so assume critical update.
762 EXPECT_TRUE(
763 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
764 // Installed version before the critical update.
765 EXPECT_TRUE(
766 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
767 .IsValid());
768 // Installed version is past the critical update.
769 EXPECT_FALSE(
770 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
771 .IsValid());
772 }
773
774 // Test the case where the critical version is the same as the to-be-installed
775 // Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalEqualsPv)776 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) {
777 MockInstallerState& installer_state(Initialize(pv_version_));
778
779 EXPECT_TRUE(installer_state.critical_update_version().Equals(
780 *pv_version_));
781 // Unable to determine the installed version, so assume critical update.
782 EXPECT_TRUE(
783 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
784 // Installed version before the critical update.
785 EXPECT_TRUE(
786 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
787 .IsValid());
788 // Installed version equals the critical update.
789 EXPECT_FALSE(
790 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
791 .IsValid());
792 }
793
794 // Test the case where the critical version is greater than the to-be-installed
795 // Chrome.
TEST_F(InstallerStateCriticalVersionTest,CriticalAfterPv)796 TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) {
797 MockInstallerState& installer_state(Initialize(high_version_));
798
799 EXPECT_TRUE(installer_state.critical_update_version().Equals(
800 *high_version_));
801 // Critical update newer than the new version.
802 EXPECT_FALSE(
803 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
804 EXPECT_FALSE(
805 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
806 .IsValid());
807 EXPECT_FALSE(
808 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
809 .IsValid());
810 }
811