• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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