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