| OLD | NEW |
| (Empty) |
| 1 // Copyright 2007-2010 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include <atlpath.h> | |
| 17 #include <atlstr.h> | |
| 18 #include "base/scoped_ptr.h" | |
| 19 #include "omaha/base/app_util.h" | |
| 20 #include "omaha/base/error.h" | |
| 21 #include "omaha/base/file.h" | |
| 22 #include "omaha/base/path.h" | |
| 23 #include "omaha/base/reg_key.h" | |
| 24 #include "omaha/base/scoped_ptr_address.h" | |
| 25 #include "omaha/base/shell.h" | |
| 26 #include "omaha/base/synchronized.h" | |
| 27 #include "omaha/base/system.h" | |
| 28 #include "omaha/base/timer.h" | |
| 29 #include "omaha/base/utils.h" | |
| 30 #include "omaha/base/vistautil.h" | |
| 31 #include "omaha/common/const_goopdate.h" | |
| 32 #include "omaha/common/goopdate_utils.h" | |
| 33 #include "omaha/common/install_manifest.h" | |
| 34 #include "omaha/common/ping_event.h" | |
| 35 #include "omaha/goopdate/app_bundle_state_initialized.h" | |
| 36 #include "omaha/goopdate/app_state_waiting_to_install.h" | |
| 37 #include "omaha/goopdate/app_unittest_base.h" | |
| 38 #include "omaha/goopdate/installer_wrapper.h" | |
| 39 #include "omaha/goopdate/install_manager.h" | |
| 40 #include "omaha/testing/unit_test.h" | |
| 41 | |
| 42 using ::testing::_; | |
| 43 using ::testing::Return; | |
| 44 | |
| 45 namespace omaha { | |
| 46 | |
| 47 // TODO(omaha): there is a problem with this unit test. The model is built | |
| 48 // bottom up. This makes it impossible to set the references to parents. Will | |
| 49 // have to fix the code, eventually using Builder DP to create a bunch of | |
| 50 // models containing bundles, apps, and such. | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 const TCHAR kAppId[] = _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}"); | |
| 55 const GUID kAppGuid = {0xB18BC01B, 0xE0BD, 0x4BF0, | |
| 56 {0xA3, 0x3E, 0x11, 0x33, 0x05, 0x5E, 0x5F, 0xDE}}; | |
| 57 const TCHAR kApp2Id[] = _T("{85794B39-42E5-457c-B567-4A0F2A0FB272}"); | |
| 58 | |
| 59 const TCHAR kFullAppClientsKeyPath[] = | |
| 60 _T("HKCU\\Software\\") SHORT_COMPANY_NAME _T("\\") PRODUCT_NAME | |
| 61 _T("\\Clients\\{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}"); | |
| 62 const TCHAR kFullAppClientStateKeyPath[] = | |
| 63 _T("HKCU\\Software\\") SHORT_COMPANY_NAME _T("\\") PRODUCT_NAME | |
| 64 _T("\\ClientState\\{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}"); | |
| 65 const TCHAR kFullFooAppClientKeyPath[] = | |
| 66 _T("HKLM\\Software\\") SHORT_COMPANY_NAME _T("\\") PRODUCT_NAME | |
| 67 _T("\\Clients\\{D6B08267-B440-4C85-9F79-E195E80D9937}"); | |
| 68 const TCHAR kFullFooAppClientStateKeyPath[] = | |
| 69 _T("HKLM\\Software\\") SHORT_COMPANY_NAME _T("\\") PRODUCT_NAME | |
| 70 _T("\\ClientState\\{D6B08267-B440-4C85-9F79-E195E80D9937}"); | |
| 71 | |
| 72 const TCHAR kFullApp2ClientsKeyPath[] = | |
| 73 _T("HKCU\\Software\\") SHORT_COMPANY_NAME _T("\\") PRODUCT_NAME | |
| 74 _T("\\Clients\\{85794B39-42E5-457c-B567-4A0F2A0FB272}"); | |
| 75 | |
| 76 const TCHAR kSetupFooV1RelativeLocation[] = | |
| 77 _T("unittest_support\\test_foo_v1.0.101.0.msi"); | |
| 78 const TCHAR kFooId[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}"); | |
| 79 const TCHAR kFooVersion[] = _T("1.0.101.0"); | |
| 80 const TCHAR kFooInstallerBarPropertyArg[] = _T("PROPBAR=7"); | |
| 81 const TCHAR kFooInstallerBarValueName[] = _T("propbar"); | |
| 82 | |
| 83 // Values related to using cmd.exe as an "installer". | |
| 84 const TCHAR kCmdExecutable[] = _T("cmd.exe"); | |
| 85 const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s"); | |
| 86 const TCHAR kExecuteTwoCommandsFormat[] = _T("\"%s & %s\""); | |
| 87 | |
| 88 const TCHAR kMsiInstallerBusyErrorMessage[] = | |
| 89 _T("Installation failed because the Windows Installer is busy. Please ") | |
| 90 _T("wait for any installers to finish, close all installer windows, and ") | |
| 91 _T("try installing again. If this problem persists, you may need ") | |
| 92 _T("to reboot your computer."); | |
| 93 | |
| 94 const TCHAR kMsiLogFormat[] = _T("%s.log"); | |
| 95 | |
| 96 // brand, InstallTime, and LastCheckSuccess are automatically populated. | |
| 97 const int kNumAutoPopulatedValues = 3; | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 // Values and functions in installer_wrapper_unittest.cc. | |
| 102 extern const TCHAR kRegExecutable[]; | |
| 103 extern const TCHAR kSetInstallerResultTypeMsiErrorRegCmdArgs[]; | |
| 104 extern const TCHAR kMsiInstallerBusyExitCodeCmd[]; | |
| 105 extern const TCHAR kError1619MessagePrefix[]; | |
| 106 extern const int kError1619MessagePrefixLength; | |
| 107 void VerifyStringIsMsiPackageOpenFailedString(const CString& str); | |
| 108 void UninstallTestMsi(const CString& installer_path); | |
| 109 void AdjustMsiTries(InstallerWrapper* installer_wrapper); | |
| 110 | |
| 111 // TODO(omaha3): Test the rest of InstallManager. | |
| 112 class InstallManagerTest : public testing::Test { | |
| 113 virtual void SetUp() {} | |
| 114 virtual void TearDown() {} | |
| 115 }; | |
| 116 | |
| 117 class InstallManagerInstallAppTest : public AppTestBaseWithRegistryOverride { | |
| 118 protected: | |
| 119 explicit InstallManagerInstallAppTest(bool is_machine) | |
| 120 : AppTestBaseWithRegistryOverride(is_machine, false) {} | |
| 121 | |
| 122 static void SetUpTestCase() { | |
| 123 CString system_path; | |
| 124 EXPECT_SUCCEEDED(Shell::GetSpecialFolder(CSIDL_SYSTEM, | |
| 125 false, | |
| 126 &system_path)); | |
| 127 EXPECT_FALSE(system_path.IsEmpty()); | |
| 128 cmd_exe_dir_ += system_path; | |
| 129 | |
| 130 CPath cmd_exe_path; | |
| 131 cmd_exe_path.Combine(system_path, kCmdExecutable); | |
| 132 EXPECT_TRUE(File::Exists(cmd_exe_path)); | |
| 133 | |
| 134 CPath reg_path; | |
| 135 reg_path.Combine(system_path, kRegExecutable); | |
| 136 set_installer_result_type_msi_error_cmd_.Format( | |
| 137 _T("%s %s"), | |
| 138 reg_path, kSetInstallerResultTypeMsiErrorRegCmdArgs); | |
| 139 } | |
| 140 | |
| 141 virtual void SetUp() { | |
| 142 AppTestBaseWithRegistryOverride::SetUp(); | |
| 143 | |
| 144 installer_wrapper_.reset(new InstallerWrapper(is_machine_)); | |
| 145 EXPECT_SUCCEEDED(installer_wrapper_->Initialize()); | |
| 146 | |
| 147 ASSERT_SUCCEEDED(app_bundle_->createApp(CComBSTR(kAppId), &app_)); | |
| 148 | |
| 149 SetAppStateWaitingToInstall(app_); | |
| 150 } | |
| 151 | |
| 152 HRESULT InstallApp(const CString& existing_version, | |
| 153 App* app, | |
| 154 const CString& dir) { | |
| 155 ASSERT1(app); | |
| 156 return InstallManager::InstallApp(is_machine_, | |
| 157 NULL, | |
| 158 existing_version, | |
| 159 app->model()->lock(), | |
| 160 installer_wrapper_.get(), | |
| 161 app, | |
| 162 dir); | |
| 163 } | |
| 164 | |
| 165 void SetArgumentsInManifest(const CString& arguments, | |
| 166 const CString& expected_version, | |
| 167 App* app) { | |
| 168 ASSERT1(app); | |
| 169 | |
| 170 // TODO(omaha3): Consider using a mock object. | |
| 171 xml::InstallManifest* install_manifest = new xml::InstallManifest; | |
| 172 install_manifest->version = expected_version; | |
| 173 | |
| 174 xml::InstallAction install_event_action; | |
| 175 install_event_action.install_event = xml::InstallAction::kInstall; | |
| 176 install_event_action.needs_admin = is_machine_ ? NEEDS_ADMIN_YES : | |
| 177 NEEDS_ADMIN_NO; | |
| 178 // TODO(omaha3): Set install_event_action.program_to_run? | |
| 179 install_event_action.program_arguments = arguments; | |
| 180 | |
| 181 install_manifest->install_actions.push_back(install_event_action); | |
| 182 app->next_version()->set_install_manifest(install_manifest); | |
| 183 } | |
| 184 | |
| 185 void SetPostInstallActionInManifest(SuccessfulInstallAction success_action, | |
| 186 const CString& success_url, | |
| 187 bool terminate_all_browsers, | |
| 188 App* app) { | |
| 189 xml::InstallManifest* install_manifest = new xml::InstallManifest; | |
| 190 install_manifest->version = _T("1.2.3.4"); | |
| 191 | |
| 192 xml::InstallAction post_install_event_action; | |
| 193 post_install_event_action.install_event = xml::InstallAction::kPostInstall; | |
| 194 post_install_event_action.needs_admin = is_machine_ ? NEEDS_ADMIN_YES : | |
| 195 NEEDS_ADMIN_NO; | |
| 196 post_install_event_action.success_url = success_url; | |
| 197 post_install_event_action.terminate_all_browsers = terminate_all_browsers; | |
| 198 post_install_event_action.success_action = success_action; | |
| 199 install_manifest->install_actions.push_back(post_install_event_action); | |
| 200 app->next_version()->set_install_manifest(install_manifest); | |
| 201 } | |
| 202 | |
| 203 static void SetAppStateWaitingToInstall(App* app) { | |
| 204 SetAppStateForUnitTest(app, new fsm::AppStateWaitingToInstall); | |
| 205 } | |
| 206 | |
| 207 static HRESULT GetResultCode(const App* app) { | |
| 208 return app->error_context_.error_code; | |
| 209 } | |
| 210 | |
| 211 static CString GetCompletionMessage(const App* app) { | |
| 212 return app->completion_message_; | |
| 213 } | |
| 214 | |
| 215 static PingEvent::Results GetCompletionResult(const App* app) { | |
| 216 return app->completion_result_; | |
| 217 } | |
| 218 | |
| 219 static CString GetPostInstallLaunchCommandLine(const App* app) { | |
| 220 return app->post_install_launch_command_line_; | |
| 221 } | |
| 222 | |
| 223 static CString GetPostInstallUrl(const App* app) { | |
| 224 return app->post_install_url_; | |
| 225 } | |
| 226 | |
| 227 static PostInstallAction GetPostInstallAction(const App* app) { | |
| 228 return app->post_install_action_; | |
| 229 } | |
| 230 | |
| 231 static void PopulateSuccessfulInstallResultInfo( | |
| 232 const App* app, InstallerResultInfo* result_info) { | |
| 233 return InstallManager::PopulateSuccessfulInstallResultInfo( | |
| 234 app, result_info); | |
| 235 } | |
| 236 | |
| 237 scoped_ptr<InstallerWrapper> installer_wrapper_; | |
| 238 | |
| 239 App* app_; | |
| 240 | |
| 241 static CPath cmd_exe_dir_; | |
| 242 static CString set_installer_result_type_msi_error_cmd_; | |
| 243 }; | |
| 244 | |
| 245 CPath InstallManagerInstallAppTest::cmd_exe_dir_; | |
| 246 CString InstallManagerInstallAppTest::set_installer_result_type_msi_error_cmd_; | |
| 247 | |
| 248 class InstallManagerInstallAppMachineTest | |
| 249 : public InstallManagerInstallAppTest { | |
| 250 protected: | |
| 251 InstallManagerInstallAppMachineTest() | |
| 252 : InstallManagerInstallAppTest(true) { | |
| 253 } | |
| 254 }; | |
| 255 | |
| 256 class InstallManagerInstallAppUserTest : public InstallManagerInstallAppTest { | |
| 257 protected: | |
| 258 InstallManagerInstallAppUserTest() | |
| 259 : InstallManagerInstallAppTest(false) { | |
| 260 } | |
| 261 }; | |
| 262 | |
| 263 // | |
| 264 // Helper method tests | |
| 265 // | |
| 266 | |
| 267 // TODO(omaha3): We may replace these with the tests from | |
| 268 // installer_wrapper_unittest.cc if CheckApplicationRegistration() is moved to | |
| 269 // InstallManager. | |
| 270 #if 0 | |
| 271 TEST_F(InstallManagerInstallAppUserTest, | |
| 272 CheckApplicationRegistration_FailsWhenClientsKeyAbsent) { | |
| 273 AppData app_data(kAppGuid, is_machine_); | |
| 274 Job job(false, &ping_); | |
| 275 job.set_app_data(app_data); | |
| 276 | |
| 277 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY, | |
| 278 CheckApplicationRegistration(CString(), &job)); | |
| 279 | |
| 280 EXPECT_FALSE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 281 EXPECT_FALSE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 282 } | |
| 283 | |
| 284 TEST_F(InstallManagerInstallAppUserTest, | |
| 285 CheckApplicationRegistration_FailsWhenVersionValueAbsent) { | |
| 286 ASSERT_SUCCEEDED(RegKey::CreateKey(kFullAppClientsKeyPath)); | |
| 287 | |
| 288 AppData app_data(kAppGuid, is_machine_); | |
| 289 Job job(false, &ping_); | |
| 290 job.set_app_data(app_data); | |
| 291 | |
| 292 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY, | |
| 293 CheckApplicationRegistration(CString(), &job)); | |
| 294 | |
| 295 EXPECT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 296 EXPECT_FALSE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 297 } | |
| 298 | |
| 299 TEST_F(InstallManagerInstallAppUserTest, | |
| 300 CheckApplicationRegistration_SucceedsWhenStateKeyAbsent) { | |
| 301 ASSERT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 302 kRegValueProductVersion, | |
| 303 _T("0.9.68.4"))); | |
| 304 | |
| 305 AppData app_data(kAppGuid, is_machine_); | |
| 306 Job job(false, &ping_); | |
| 307 job.set_app_data(app_data); | |
| 308 | |
| 309 EXPECT_SUCCEEDED(CheckApplicationRegistration(CString(), &job)); | |
| 310 } | |
| 311 | |
| 312 TEST_F(InstallManagerInstallAppUserTest, | |
| 313 CheckApplicationRegistration_SucceedsWhenStateKeyPresent) { | |
| 314 const TCHAR* keys_to_create[] = {kFullAppClientsKeyPath, | |
| 315 kFullAppClientStateKeyPath}; | |
| 316 ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2)); | |
| 317 ASSERT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 318 ASSERT_TRUE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 319 ASSERT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 320 kRegValueProductVersion, | |
| 321 _T("0.9.70.0"))); | |
| 322 | |
| 323 AppData app_data(kAppGuid, is_machine_); | |
| 324 Job job(false, &ping_); | |
| 325 job.set_app_data(app_data); | |
| 326 | |
| 327 // The install should succeed even if the version is the same. | |
| 328 EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.0"), &job)); | |
| 329 } | |
| 330 | |
| 331 TEST_F(InstallManagerInstallAppUserTest, | |
| 332 CheckApplicationRegistration_UpdateSucceeds) { | |
| 333 const TCHAR* keys_to_create[] = {kFullAppClientsKeyPath, | |
| 334 kFullAppClientStateKeyPath}; | |
| 335 ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2)); | |
| 336 ASSERT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 337 ASSERT_TRUE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 338 ASSERT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 339 kRegValueProductVersion, | |
| 340 _T("0.9.70.0"))); | |
| 341 | |
| 342 AppData app_data(kAppGuid, is_machine_); | |
| 343 Job job(true, &ping_); | |
| 344 job.set_app_data(app_data); | |
| 345 | |
| 346 EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.1"), &job)); | |
| 347 } | |
| 348 | |
| 349 TEST_F(InstallManagerInstallAppUserTest, | |
| 350 CheckApplicationRegistration_UpdateFailsWhenVersionDoesNotChange) { | |
| 351 const TCHAR* keys_to_create[] = {kFullAppClientsKeyPath, | |
| 352 kFullAppClientStateKeyPath}; | |
| 353 ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, | |
| 354 arraysize(keys_to_create))); | |
| 355 ASSERT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 356 ASSERT_TRUE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 357 ASSERT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 358 kRegValueProductVersion, | |
| 359 _T("0.9.70.0"))); | |
| 360 | |
| 361 AppData app_data(kAppGuid, is_machine_); | |
| 362 Job job(true, &ping_); | |
| 363 job.set_app_data(app_data); | |
| 364 | |
| 365 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION, | |
| 366 CheckApplicationRegistration(_T("0.9.70.0"), &job)); | |
| 367 } | |
| 368 #endif | |
| 369 | |
| 370 // | |
| 371 // Negative Tests | |
| 372 // | |
| 373 | |
| 374 TEST_F(InstallManagerInstallAppUserTest, | |
| 375 InstallApp_InstallerWithoutFilenameExtension) { | |
| 376 app_->next_version()->AddPackage(_T("foo"), 100, _T("hash")); | |
| 377 | |
| 378 // TODO(omaha): We should be able to eliminate this. | |
| 379 SetArgumentsInManifest(CString(), _T("1.2.3.4"), app_); | |
| 380 | |
| 381 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, | |
| 382 InstallApp(_T(""), app_, _T("c:\\temp"))); | |
| 383 | |
| 384 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 385 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 386 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, GetResultCode(app_)); | |
| 387 EXPECT_STREQ( | |
| 388 _T("The installer filename c:\\temp\\foo is invalid or unsupported."), | |
| 389 GetCompletionMessage(app_)); | |
| 390 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 391 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 392 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 393 } | |
| 394 | |
| 395 TEST_F(InstallManagerInstallAppUserTest, | |
| 396 InstallApp_UnsupportedInstallerFilenameExtension) { | |
| 397 app_->next_version()->AddPackage(_T("foo.bar"), 100, _T("hash")); | |
| 398 | |
| 399 // TODO(omaha): We should be able to eliminate this. | |
| 400 SetArgumentsInManifest(CString(), _T("1.2.3.4"), app_); | |
| 401 | |
| 402 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, | |
| 403 InstallApp(_T(""), app_, _T("c:\\temp"))); | |
| 404 | |
| 405 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 406 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 407 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, GetResultCode(app_)); | |
| 408 EXPECT_STREQ( | |
| 409 _T("The installer filename c:\\temp\\foo.bar is invalid or unsupported."), | |
| 410 GetCompletionMessage(app_)); | |
| 411 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 412 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 413 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 414 } | |
| 415 | |
| 416 TEST_F(InstallManagerInstallAppUserTest, InstallApp_InstallerEmtpyFilename) { | |
| 417 // Package asserts that the filename and file path are not NULL. | |
| 418 ExpectAsserts expect_asserts; | |
| 419 | |
| 420 app_->next_version()->AddPackage(_T(""), 100, _T("hash")); | |
| 421 // This test does not call | |
| 422 // app_->next_version()->GetPackage(0)->set_local_file_path(). | |
| 423 | |
| 424 // TODO(omaha): We should be able to eliminate this. | |
| 425 SetArgumentsInManifest(CString(), _T("1.2.3.4"), app_); | |
| 426 | |
| 427 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, | |
| 428 InstallApp(_T(""), app_, NULL)); | |
| 429 | |
| 430 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 431 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 432 EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, GetResultCode(app_)); | |
| 433 EXPECT_STREQ(_T("The installer filename \\ is invalid or unsupported."), | |
| 434 GetCompletionMessage(app_)); | |
| 435 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 436 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 437 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 438 } | |
| 439 | |
| 440 TEST_F(InstallManagerInstallAppUserTest, InstallApp_NoPackage) { | |
| 441 // InstallApp asserts that there is at least one package. | |
| 442 ExpectAsserts expect_asserts; | |
| 443 | |
| 444 EXPECT_EQ(E_FAIL, InstallApp(_T(""), app_, NULL)); | |
| 445 | |
| 446 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 447 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 448 EXPECT_EQ(E_FAIL, GetResultCode(app_)); | |
| 449 EXPECT_STREQ( | |
| 450 _T("Installation failed. Please try again."), | |
| 451 GetCompletionMessage(app_)); | |
| 452 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 453 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 454 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 455 } | |
| 456 | |
| 457 TEST_F(InstallManagerInstallAppUserTest, InstallApp_ExeFileDoesNotExist) { | |
| 458 app_->next_version()->AddPackage(_T("foo.exe"), 100, _T("hash")); | |
| 459 | |
| 460 // TODO(omaha): We should be able to eliminate this. | |
| 461 SetArgumentsInManifest(CString(), _T("1.2.3.4"), app_); | |
| 462 | |
| 463 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, | |
| 464 InstallApp(_T(""), app_, _T("c:\\temp"))); | |
| 465 | |
| 466 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 467 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 468 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, GetResultCode(app_)); | |
| 469 EXPECT_STREQ(_T("The installer failed to start."), | |
| 470 GetCompletionMessage(app_)); | |
| 471 | |
| 472 EXPECT_FALSE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 473 EXPECT_FALSE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 474 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 475 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 476 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 477 } | |
| 478 | |
| 479 // | |
| 480 // EXE Installer Tests | |
| 481 // | |
| 482 | |
| 483 // TODO(omaha3): Add InstallApp_ExeInstallerWithoutArgumentsSucceeds using | |
| 484 // SaveArguments.exe. Do the same in InstallerWrapperUserTest. | |
| 485 | |
| 486 // TODO(omaha3): Add InstallApp tests that cause | |
| 487 // ReadInstallerRegistrationValues & CheckApplicationRegistration to fail. | |
| 488 | |
| 489 // This test uses cmd.exe as an installer that leaves the payload | |
| 490 // kPayloadFileName. | |
| 491 TEST_F(InstallManagerInstallAppUserTest, | |
| 492 InstallApp_ExeInstallerWithArgumentsSucceeds) { | |
| 493 const TCHAR kPayloadFileName[] = _T("exe_payload.txt"); | |
| 494 const TCHAR kCommandToExecute[] = _T("echo \"hi\" > %s"); | |
| 495 | |
| 496 CString full_command_to_execute; | |
| 497 full_command_to_execute.Format(kCommandToExecute, kPayloadFileName); | |
| 498 CString arguments; | |
| 499 arguments.Format(kExecuteCommandAndTerminateSwitch, full_command_to_execute); | |
| 500 | |
| 501 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName)); | |
| 502 EXPECT_FALSE(File::Exists(kPayloadFileName)); | |
| 503 | |
| 504 // Create the Clients key since this isn't an actual installer. | |
| 505 EXPECT_SUCCEEDED(RegKey::CreateKey(kFullAppClientsKeyPath)); | |
| 506 EXPECT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 507 EXPECT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 508 kRegValueProductVersion, | |
| 509 _T("0.10.69.5"))); | |
| 510 | |
| 511 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 512 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Exe App")))); | |
| 513 | |
| 514 SetArgumentsInManifest(arguments, _T("0.10.69.5"), app_); | |
| 515 | |
| 516 EXPECT_SUCCEEDED(InstallApp(_T(""), app_, cmd_exe_dir_)); | |
| 517 | |
| 518 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 519 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 520 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 521 EXPECT_STREQ(_T("Thanks for installing."), GetCompletionMessage(app_)); | |
| 522 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 523 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 524 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 525 | |
| 526 RegKey state_key; | |
| 527 EXPECT_SUCCEEDED(state_key.Open(kFullAppClientStateKeyPath)); | |
| 528 EXPECT_EQ(1 + kNumAutoPopulatedValues, state_key.GetValueCount()); | |
| 529 EXPECT_STREQ(_T("0.10.69.5"), GetSzValue(kFullAppClientStateKeyPath, | |
| 530 kRegValueProductVersion)); | |
| 531 | |
| 532 EXPECT_TRUE(File::Exists(kPayloadFileName)); | |
| 533 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName)); | |
| 534 } | |
| 535 | |
| 536 TEST_F(InstallManagerInstallAppUserTest, | |
| 537 InstallApp_ExeInstallerReturnsNonZeroExitCode) { | |
| 538 const TCHAR kCommandToExecute[] = _T("exit 1"); | |
| 539 | |
| 540 CString arguments; | |
| 541 arguments.Format(kExecuteCommandAndTerminateSwitch, kCommandToExecute); | |
| 542 | |
| 543 // Create the Clients key since this isn't an actual installer. | |
| 544 ASSERT_SUCCEEDED(RegKey::CreateKey(kFullAppClientsKeyPath)); | |
| 545 ASSERT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 546 ASSERT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 547 kRegValueProductVersion, | |
| 548 _T("0.10.69.5"))); | |
| 549 | |
| 550 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 551 | |
| 552 SetArgumentsInManifest(arguments, _T("0.10.69.5"), app_); | |
| 553 | |
| 554 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED, | |
| 555 InstallApp(_T(""), app_, cmd_exe_dir_)); | |
| 556 | |
| 557 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 558 EXPECT_EQ(PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER, | |
| 559 GetCompletionResult(app_)); | |
| 560 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED, GetResultCode(app_)); | |
| 561 EXPECT_STREQ(_T("The installer encountered error 1."), | |
| 562 GetCompletionMessage(app_)); | |
| 563 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 564 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 565 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 566 } | |
| 567 | |
| 568 TEST_F(InstallManagerInstallAppMachineTest, InstallApp_MsiInstallerSucceeds) { | |
| 569 if (!vista_util::IsUserAdmin()) { | |
| 570 std::wcout << _T("\tTest did not run because the user is not an admin.") | |
| 571 << std::endl; | |
| 572 return; | |
| 573 } | |
| 574 | |
| 575 const CString kIid = _T("{F7598FEE-4BA9-4755-A1FC-6EB0A6F3D126}"); | |
| 576 | |
| 577 // We can't fake the registry keys because we are interacting with a real | |
| 578 // installer. | |
| 579 RestoreRegistryHives(); | |
| 580 | |
| 581 AdjustMsiTries(installer_wrapper_.get()); | |
| 582 | |
| 583 CString installer_dir(app_util::GetCurrentModuleDirectory()); | |
| 584 | |
| 585 CString installer_full_path( | |
| 586 ConcatenatePath(installer_dir, kSetupFooV1RelativeLocation)); | |
| 587 ASSERT_TRUE(File::Exists(installer_full_path)); | |
| 588 | |
| 589 CString installer_log_full_path; | |
| 590 installer_log_full_path.Format(kMsiLogFormat, installer_full_path); | |
| 591 | |
| 592 ASSERT_SUCCEEDED(File::Remove(installer_log_full_path)); | |
| 593 ASSERT_FALSE(File::Exists(installer_log_full_path)); | |
| 594 | |
| 595 RegKey::DeleteKey(kFullFooAppClientKeyPath); | |
| 596 ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 597 RegKey::DeleteKey(kFullFooAppClientStateKeyPath); | |
| 598 ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); | |
| 599 | |
| 600 // Accepting the EULA prevents "eulaaccepted" value from being written. | |
| 601 EXPECT_SUCCEEDED(app_->put_isEulaAccepted(VARIANT_TRUE)); | |
| 602 | |
| 603 // TODO(omaha): This should be just a filename. | |
| 604 app_->next_version()->AddPackage(kSetupFooV1RelativeLocation, | |
| 605 100, _T("hash")); | |
| 606 app_->set_app_guid(StringToGuid(kFooId)); | |
| 607 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Foo")))); | |
| 608 EXPECT_SUCCEEDED(app_->put_iid(CComBSTR(kIid))); | |
| 609 | |
| 610 // TODO(omaha): We should be able to eliminate this. | |
| 611 SetArgumentsInManifest(CString(), kFooVersion, app_); | |
| 612 | |
| 613 EXPECT_SUCCEEDED(InstallApp(_T(""), app_, installer_dir)); | |
| 614 | |
| 615 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 616 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 617 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 618 EXPECT_STREQ(_T("Thanks for installing."), | |
| 619 GetCompletionMessage(app_)); | |
| 620 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 621 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 622 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 623 | |
| 624 EXPECT_TRUE(File::Exists(installer_log_full_path)); | |
| 625 | |
| 626 EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 627 EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); | |
| 628 RegKey state_key; | |
| 629 EXPECT_SUCCEEDED(state_key.Open(kFullFooAppClientStateKeyPath)); | |
| 630 EXPECT_EQ(2 + kNumAutoPopulatedValues, state_key.GetValueCount()); | |
| 631 EXPECT_STREQ(kFooVersion, GetSzValue(kFullFooAppClientStateKeyPath, | |
| 632 kRegValueProductVersion)); | |
| 633 EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, | |
| 634 kRegValueLanguage)); | |
| 635 EXPECT_STREQ(kIid, GetSzValue(kFullFooAppClientStateKeyPath, | |
| 636 kRegValueInstallationId)); | |
| 637 | |
| 638 // Verify the installer did not write a value that is to be written only in | |
| 639 // the presence of an MSI property that was not specified. | |
| 640 EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientKeyPath, | |
| 641 kFooInstallerBarValueName)); | |
| 642 | |
| 643 UninstallTestMsi(installer_full_path); | |
| 644 | |
| 645 EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 646 EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath)); | |
| 647 } | |
| 648 | |
| 649 TEST_F(InstallManagerInstallAppMachineTest, | |
| 650 InstallApp_MsiInstallerWithArgumentSucceeds) { | |
| 651 if (!vista_util::IsUserAdmin()) { | |
| 652 std::wcout << _T("\tTest did not run because the user is not an admin.") | |
| 653 << std::endl; | |
| 654 return; | |
| 655 } | |
| 656 | |
| 657 // We can't fake the registry keys because we are interacting with a real | |
| 658 // installer. | |
| 659 RestoreRegistryHives(); | |
| 660 | |
| 661 AdjustMsiTries(installer_wrapper_.get()); | |
| 662 | |
| 663 CString installer_dir(app_util::GetCurrentModuleDirectory()); | |
| 664 | |
| 665 CString installer_full_path( | |
| 666 ConcatenatePath(installer_dir, kSetupFooV1RelativeLocation)); | |
| 667 ASSERT_TRUE(File::Exists(installer_full_path)); | |
| 668 | |
| 669 CString installer_log_full_path; | |
| 670 installer_log_full_path.Format(kMsiLogFormat, installer_full_path); | |
| 671 | |
| 672 ASSERT_SUCCEEDED(File::Remove(installer_log_full_path)); | |
| 673 ASSERT_FALSE(File::Exists(installer_log_full_path)); | |
| 674 | |
| 675 RegKey::DeleteKey(kFullFooAppClientKeyPath); | |
| 676 ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 677 RegKey::DeleteKey(kFullFooAppClientStateKeyPath); | |
| 678 ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); | |
| 679 | |
| 680 // Write an iid to verify it gets deleted below. | |
| 681 EXPECT_SUCCEEDED( | |
| 682 RegKey::SetValue(kFullFooAppClientStateKeyPath, | |
| 683 kRegValueInstallationId, | |
| 684 _T("{A30B6C0A-B491-473e-9D24-E1AC1BC1D42F}"))); | |
| 685 | |
| 686 // Accepting the EULA prevents "eulaaccepted" value from being written. | |
| 687 EXPECT_SUCCEEDED(app_->put_isEulaAccepted(VARIANT_TRUE)); | |
| 688 | |
| 689 // TODO(omaha): This should be just a filename. | |
| 690 app_->next_version()->AddPackage(kSetupFooV1RelativeLocation, | |
| 691 100, _T("hash")); | |
| 692 app_->set_app_guid(StringToGuid(kFooId)); | |
| 693 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Foo")))); | |
| 694 | |
| 695 SetArgumentsInManifest(kFooInstallerBarPropertyArg, kFooVersion, app_); | |
| 696 | |
| 697 EXPECT_SUCCEEDED(InstallApp(_T(""), app_, installer_dir)); | |
| 698 | |
| 699 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 700 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 701 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 702 EXPECT_STREQ(_T("Thanks for installing."), | |
| 703 GetCompletionMessage(app_)); | |
| 704 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 705 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 706 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 707 | |
| 708 EXPECT_TRUE(File::Exists(installer_log_full_path)); | |
| 709 | |
| 710 EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 711 EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); | |
| 712 RegKey state_key; | |
| 713 EXPECT_SUCCEEDED(state_key.Open(kFullFooAppClientStateKeyPath)); | |
| 714 EXPECT_EQ(1 + kNumAutoPopulatedValues, state_key.GetValueCount()); | |
| 715 EXPECT_STREQ(kFooVersion, GetSzValue(kFullFooAppClientStateKeyPath, | |
| 716 kRegValueProductVersion)); | |
| 717 EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, | |
| 718 kRegValueLanguage)); | |
| 719 EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, | |
| 720 kRegValueInstallationId)); | |
| 721 | |
| 722 EXPECT_TRUE(RegKey::HasValue(kFullFooAppClientKeyPath, | |
| 723 kFooInstallerBarValueName)); | |
| 724 DWORD barprop_value; | |
| 725 EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientKeyPath, | |
| 726 kFooInstallerBarValueName, | |
| 727 &barprop_value)); | |
| 728 EXPECT_EQ(7, barprop_value); | |
| 729 | |
| 730 UninstallTestMsi(installer_full_path); | |
| 731 | |
| 732 EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); | |
| 733 EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath)); | |
| 734 } | |
| 735 | |
| 736 // The use of kGoogleUpdateAppId is the key to this test. | |
| 737 // Note that the version is not changed - this is the normal self-update case. | |
| 738 // Among other things, this test verifies that CheckApplicationRegistration() is | |
| 739 // not called for self-updates. | |
| 740 TEST_F(InstallManagerInstallAppUserTest, InstallApp_UpdateOmahaSucceeds) { | |
| 741 CString arguments; | |
| 742 arguments.Format(kExecuteCommandAndTerminateSwitch, _T("")); | |
| 743 | |
| 744 const CString kExistingVersion(_T("0.9.69.5")); | |
| 745 | |
| 746 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 747 app_->set_app_guid(StringToGuid(kGoogleUpdateAppId)); | |
| 748 | |
| 749 // TODO(omaha3): This isn't supported yet. | |
| 750 #if 0 | |
| 751 isupdate = true | |
| 752 #endif | |
| 753 | |
| 754 SetArgumentsInManifest(arguments, _T("1.2.9.8"), app_); | |
| 755 | |
| 756 // Because we don't actually run the Omaha installer, we need to make sure | |
| 757 // its Clients key and pv value exist to avoid an error. | |
| 758 ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE)); | |
| 759 ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); | |
| 760 ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE, | |
| 761 kRegValueProductVersion, | |
| 762 kExistingVersion)); | |
| 763 | |
| 764 EXPECT_SUCCEEDED(InstallApp(kExistingVersion, app_, cmd_exe_dir_)); | |
| 765 | |
| 766 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 767 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 768 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 769 EXPECT_STREQ(_T("Thanks for installing."), GetCompletionMessage(app_)); | |
| 770 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 771 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 772 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 773 | |
| 774 EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); | |
| 775 CString version; | |
| 776 EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENTS_GOOPDATE, | |
| 777 kRegValueProductVersion, | |
| 778 &version)); | |
| 779 EXPECT_STREQ(kExistingVersion, version); | |
| 780 } | |
| 781 | |
| 782 // The main purpose of this test is to ensure that self-updates don't fail if | |
| 783 // Omaha's Clients key doesn't exist for some reason. | |
| 784 // In other words, it tests that CheckApplicationRegistration() is not called. | |
| 785 TEST_F(InstallManagerInstallAppUserTest, | |
| 786 InstallApp_UpdateOmahaSucceedsWhenClientsKeyAbsent) { | |
| 787 CString arguments; | |
| 788 arguments.Format(kExecuteCommandAndTerminateSwitch, _T("")); | |
| 789 | |
| 790 const CString kExistingVersion(_T("0.9.69.5")); | |
| 791 | |
| 792 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 793 app_->set_app_guid(StringToGuid(kGoogleUpdateAppId)); | |
| 794 | |
| 795 // TODO(omaha3): This isn't supported yet. | |
| 796 #if 0 | |
| 797 isupdate = true | |
| 798 #endif | |
| 799 | |
| 800 SetArgumentsInManifest(arguments, _T("1.2.9.8"), app_); | |
| 801 | |
| 802 EXPECT_SUCCEEDED(InstallApp(kExistingVersion, app_, cmd_exe_dir_)); | |
| 803 | |
| 804 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 805 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 806 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 807 EXPECT_STREQ(_T("Thanks for installing."), GetCompletionMessage(app_)); | |
| 808 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 809 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 810 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 811 | |
| 812 EXPECT_FALSE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); | |
| 813 } | |
| 814 | |
| 815 TEST_F(InstallManagerInstallAppUserTest, | |
| 816 InstallApp_InstallerDoesNotWriteClientsKey) { | |
| 817 CString arguments; | |
| 818 arguments.Format(kExecuteCommandAndTerminateSwitch, _T("")); | |
| 819 | |
| 820 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 821 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Some App")))); | |
| 822 | |
| 823 SetArgumentsInManifest(arguments, _T("5.6.7.8"), app_); | |
| 824 | |
| 825 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY, | |
| 826 InstallApp(_T(""), app_, cmd_exe_dir_)); | |
| 827 | |
| 828 EXPECT_FALSE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 829 EXPECT_FALSE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 830 | |
| 831 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 832 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 833 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY, | |
| 834 GetResultCode(app_)); | |
| 835 EXPECT_STREQ( | |
| 836 _T("Installation failed. Please try again."), | |
| 837 GetCompletionMessage(app_)); | |
| 838 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 839 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 840 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 841 } | |
| 842 | |
| 843 // TODO(omaha3): Test for GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION | |
| 844 // once is_update is supported. | |
| 845 | |
| 846 TEST_F(InstallManagerInstallAppUserTest, | |
| 847 InstallApp_InstallerFailureMsiFileDoesNotExist) { | |
| 848 CPath msi_dir(app_util::GetTempDir()); | |
| 849 CPath msi_path(msi_dir); | |
| 850 msi_path.Append(_T("foo.msi")); | |
| 851 const CString log_path = msi_path + _T(".log"); | |
| 852 | |
| 853 AdjustMsiTries(installer_wrapper_.get()); | |
| 854 | |
| 855 ASSERT_SUCCEEDED(File::Remove(log_path)); | |
| 856 ASSERT_FALSE(File::Exists(log_path)); | |
| 857 | |
| 858 app_->next_version()->AddPackage(_T("foo.msi"), 100, _T("hash")); | |
| 859 | |
| 860 // TODO(omaha): We should be able to eliminate this. | |
| 861 SetArgumentsInManifest(CString(), _T("1.2.3.4"), app_); | |
| 862 | |
| 863 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED, | |
| 864 InstallApp(_T(""), app_, msi_dir)); | |
| 865 | |
| 866 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 867 EXPECT_EQ(PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI, | |
| 868 GetCompletionResult(app_)); | |
| 869 EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED, GetResultCode(app_)); | |
| 870 const CString message = GetCompletionMessage(app_); | |
| 871 EXPECT_STREQ(kError1619MessagePrefix, | |
| 872 message.Left(kError1619MessagePrefixLength)); | |
| 873 VerifyStringIsMsiPackageOpenFailedString( | |
| 874 message.Mid(kError1619MessagePrefixLength)); | |
| 875 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 876 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 877 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 878 | |
| 879 // msiexec creates an empty log file. | |
| 880 EXPECT_TRUE(File::Exists(log_path)); | |
| 881 EXPECT_SUCCEEDED(File::Remove(log_path)); | |
| 882 | |
| 883 EXPECT_FALSE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 884 EXPECT_FALSE(RegKey::HasKey(kFullAppClientStateKeyPath)); | |
| 885 } | |
| 886 | |
| 887 // Simulates the MSI busy error by having an exe installer return the error | |
| 888 // as its exit code and specifying MSI error using Installer Result API. | |
| 889 // Assumes reg.exe is in the path. | |
| 890 // This works because the number of retries is set before InstallApp() and thus | |
| 891 // defaults to 1 in the InstallerWrapper. | |
| 892 TEST_F(InstallManagerInstallAppUserTest, InstallApp_MsiIsBusy_NoRetries) { | |
| 893 CString commands; | |
| 894 commands.Format(kExecuteTwoCommandsFormat, | |
| 895 set_installer_result_type_msi_error_cmd_, | |
| 896 kMsiInstallerBusyExitCodeCmd); | |
| 897 | |
| 898 CString arguments; | |
| 899 arguments.Format(kExecuteCommandAndTerminateSwitch, commands); | |
| 900 | |
| 901 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 902 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Some App")))); | |
| 903 | |
| 904 SetArgumentsInManifest(arguments, _T("1.2.3.4"), app_); | |
| 905 | |
| 906 LowResTimer install_timer(true); | |
| 907 | |
| 908 EXPECT_EQ(GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING, | |
| 909 InstallApp(_T(""), app_, cmd_exe_dir_)); | |
| 910 | |
| 911 EXPECT_GT(2, install_timer.GetSeconds()); // Check Omaha did not retry. | |
| 912 | |
| 913 EXPECT_EQ(STATE_ERROR, app_->state()); | |
| 914 // Even though the error came from the installer, the error type is not | |
| 915 // set because we have a custom error for this case. | |
| 916 EXPECT_EQ(PingEvent::EVENT_RESULT_ERROR, GetCompletionResult(app_)); | |
| 917 EXPECT_EQ(GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING, | |
| 918 GetResultCode(app_)); | |
| 919 EXPECT_STREQ(kMsiInstallerBusyErrorMessage, GetCompletionMessage(app_)); | |
| 920 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 921 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 922 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 923 } | |
| 924 | |
| 925 // This test uses cmd.exe as an installer that leaves the payload files. | |
| 926 TEST_F(InstallManagerInstallAppUserTest, InstallApp_InstallMultipleApps) { | |
| 927 const TCHAR kPayloadFileName1[] = _T("exe_payload1.txt"); | |
| 928 const TCHAR kPayloadFileName2[] = _T("exe_payload2.txt"); | |
| 929 const TCHAR kCommandToExecute[] = _T("echo \"hi\" > %s"); | |
| 930 | |
| 931 CString full_command_to_execute; | |
| 932 full_command_to_execute.Format(kCommandToExecute, kPayloadFileName1); | |
| 933 CString arguments1; | |
| 934 arguments1.Format(kExecuteCommandAndTerminateSwitch, full_command_to_execute); | |
| 935 | |
| 936 full_command_to_execute.Format(kCommandToExecute, kPayloadFileName2); | |
| 937 CString arguments2; | |
| 938 arguments2.Format(kExecuteCommandAndTerminateSwitch, full_command_to_execute); | |
| 939 | |
| 940 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName1)); | |
| 941 EXPECT_FALSE(File::Exists(kPayloadFileName1)); | |
| 942 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName2)); | |
| 943 EXPECT_FALSE(File::Exists(kPayloadFileName2)); | |
| 944 | |
| 945 // Create the Clients key since this isn't an actual installer. | |
| 946 EXPECT_SUCCEEDED(RegKey::CreateKey(kFullAppClientsKeyPath)); | |
| 947 EXPECT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 948 EXPECT_SUCCEEDED(RegKey::SetValue(kFullAppClientsKeyPath, | |
| 949 kRegValueProductVersion, | |
| 950 _T("0.10.69.5"))); | |
| 951 | |
| 952 app_->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 953 EXPECT_SUCCEEDED(app_->put_displayName(CComBSTR(_T("Exe App")))); | |
| 954 | |
| 955 SetArgumentsInManifest(arguments1, _T("0.10.69.5"), app_); | |
| 956 | |
| 957 EXPECT_SUCCEEDED(InstallApp(_T(""), app_, cmd_exe_dir_)); | |
| 958 | |
| 959 EXPECT_EQ(STATE_INSTALL_COMPLETE, app_->state()); | |
| 960 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app_)); | |
| 961 EXPECT_EQ(S_OK, GetResultCode(app_)); | |
| 962 EXPECT_STREQ(_T("Thanks for installing."), GetCompletionMessage(app_)); | |
| 963 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 964 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 965 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 966 | |
| 967 EXPECT_TRUE(File::Exists(kPayloadFileName1)); | |
| 968 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName1)); | |
| 969 | |
| 970 // Run the second installer. | |
| 971 | |
| 972 App* app2 = NULL; | |
| 973 ASSERT_SUCCEEDED(app_bundle_->createApp(CComBSTR(kApp2Id), &app2)); | |
| 974 SetAppStateWaitingToInstall(app2); | |
| 975 | |
| 976 // Create the Clients key since this isn't an actual installer. | |
| 977 EXPECT_SUCCEEDED(RegKey::CreateKey(kFullAppClientsKeyPath)); | |
| 978 EXPECT_TRUE(RegKey::HasKey(kFullAppClientsKeyPath)); | |
| 979 EXPECT_SUCCEEDED(RegKey::SetValue(kFullApp2ClientsKeyPath, | |
| 980 kRegValueProductVersion, | |
| 981 _T("0.10.69.5"))); | |
| 982 | |
| 983 app2->next_version()->AddPackage(kCmdExecutable, 100, _T("hash")); | |
| 984 EXPECT_SUCCEEDED(app2->put_displayName(CComBSTR(_T("Exe App")))); | |
| 985 | |
| 986 SetArgumentsInManifest(arguments2, _T("0.10.69.5"), app2); | |
| 987 | |
| 988 EXPECT_SUCCEEDED(InstallApp(_T(""), app2, cmd_exe_dir_)); | |
| 989 | |
| 990 EXPECT_EQ(STATE_INSTALL_COMPLETE, app2->state()); | |
| 991 EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, GetCompletionResult(app2)); | |
| 992 EXPECT_EQ(S_OK, GetResultCode(app2)); | |
| 993 EXPECT_STREQ(_T("Thanks for installing."), GetCompletionMessage(app2)); | |
| 994 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 995 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 996 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, GetPostInstallAction(app_)); | |
| 997 | |
| 998 EXPECT_TRUE(File::Exists(kPayloadFileName2)); | |
| 999 EXPECT_SUCCEEDED(File::Remove(kPayloadFileName2)); | |
| 1000 } | |
| 1001 | |
| 1002 TEST_F(InstallManagerInstallAppUserTest, | |
| 1003 PopulateSuccessfulInstallResultInfo_ExitSilentlyOnLaunchCommandWithNoComm
and) { // NOLINT | |
| 1004 SetPostInstallActionInManifest(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD, | |
| 1005 _T(""), | |
| 1006 false, | |
| 1007 app_); | |
| 1008 | |
| 1009 InstallerResultInfo result_info; | |
| 1010 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1011 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1012 EXPECT_TRUE(GetPostInstallLaunchCommandLine(app_).IsEmpty()); | |
| 1013 EXPECT_TRUE(GetPostInstallUrl(app_).IsEmpty()); | |
| 1014 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, result_info.post_install_action); | |
| 1015 } | |
| 1016 | |
| 1017 // Verify that launch command is converted to silently launch command | |
| 1018 // if success action is silently launch command. Also tests that launch cmd | |
| 1019 // takes precedence over URL. | |
| 1020 TEST_F(InstallManagerInstallAppUserTest, | |
| 1021 PopulateSuccessfulInstallResultInfo_ExitSilentlyOnLaunchCommand) { | |
| 1022 SetPostInstallActionInManifest(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD, | |
| 1023 _T("http://post_install_succeeded"), | |
| 1024 true, | |
| 1025 app_); | |
| 1026 | |
| 1027 InstallerResultInfo result_info; | |
| 1028 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1029 result_info.post_install_action = POST_INSTALL_ACTION_LAUNCH_COMMAND; | |
| 1030 result_info.post_install_launch_command_line = _T("notepad.exe"); | |
| 1031 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1032 | |
| 1033 EXPECT_EQ(POST_INSTALL_ACTION_EXIT_SILENTLY_ON_LAUNCH_COMMAND, | |
| 1034 result_info.post_install_action); | |
| 1035 } | |
| 1036 | |
| 1037 TEST_F(InstallManagerInstallAppUserTest, | |
| 1038 PopulateSuccessfulInstallResultInfo_LaunchCommandWithDefaultSuccessAction) { | |
| 1039 SetPostInstallActionInManifest(SUCCESS_ACTION_DEFAULT, | |
| 1040 _T(""), | |
| 1041 true, | |
| 1042 app_); | |
| 1043 | |
| 1044 InstallerResultInfo result_info; | |
| 1045 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1046 result_info.post_install_action = POST_INSTALL_ACTION_LAUNCH_COMMAND; | |
| 1047 result_info.post_install_launch_command_line = _T("notepad.exe"); | |
| 1048 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1049 | |
| 1050 EXPECT_EQ(POST_INSTALL_ACTION_LAUNCH_COMMAND, | |
| 1051 result_info.post_install_action); | |
| 1052 } | |
| 1053 | |
| 1054 // Verify that default install action is converted to exit silently if | |
| 1055 // if success action is exit silently. | |
| 1056 TEST_F(InstallManagerInstallAppUserTest, | |
| 1057 PopulateSuccessfulInstallResultInfo_ExitSilently) { | |
| 1058 SetPostInstallActionInManifest(SUCCESS_ACTION_EXIT_SILENTLY, | |
| 1059 _T(""), | |
| 1060 false, | |
| 1061 app_); | |
| 1062 | |
| 1063 InstallerResultInfo result_info; | |
| 1064 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1065 result_info.post_install_action = POST_INSTALL_ACTION_DEFAULT; | |
| 1066 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1067 | |
| 1068 EXPECT_EQ(POST_INSTALL_ACTION_EXIT_SILENTLY, result_info.post_install_action); | |
| 1069 } | |
| 1070 | |
| 1071 TEST_F(InstallManagerInstallAppUserTest, | |
| 1072 PopulateSuccessfulInstallResultInfo_RestartBrowser) { | |
| 1073 SetPostInstallActionInManifest(SUCCESS_ACTION_DEFAULT, | |
| 1074 _T("http://www.google.com/foo/installed_ok"), | |
| 1075 false, | |
| 1076 app_); | |
| 1077 | |
| 1078 InstallerResultInfo result_info; | |
| 1079 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1080 result_info.post_install_action = POST_INSTALL_ACTION_DEFAULT; | |
| 1081 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1082 | |
| 1083 EXPECT_EQ(POST_INSTALL_ACTION_RESTART_BROWSER, | |
| 1084 result_info.post_install_action); | |
| 1085 } | |
| 1086 | |
| 1087 TEST_F(InstallManagerInstallAppUserTest, | |
| 1088 PopulateSuccessfulInstallResultInfo_RestartAllBrowsers) { | |
| 1089 SetPostInstallActionInManifest(SUCCESS_ACTION_DEFAULT, | |
| 1090 _T("http://www.google.com/gears/installed_ok"), | |
| 1091 true, | |
| 1092 app_); | |
| 1093 | |
| 1094 InstallerResultInfo result_info; | |
| 1095 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1096 result_info.post_install_action = POST_INSTALL_ACTION_DEFAULT; | |
| 1097 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1098 | |
| 1099 EXPECT_EQ(POST_INSTALL_ACTION_RESTART_ALL_BROWSERS, | |
| 1100 result_info.post_install_action); | |
| 1101 } | |
| 1102 | |
| 1103 TEST_F(InstallManagerInstallAppUserTest, | |
| 1104 PopulateSuccessfulInstallResultInfo_NoPostInstallUrl) { | |
| 1105 SetPostInstallActionInManifest(SUCCESS_ACTION_DEFAULT, | |
| 1106 _T(""), | |
| 1107 true, | |
| 1108 app_); | |
| 1109 | |
| 1110 InstallerResultInfo result_info; | |
| 1111 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1112 result_info.post_install_action = POST_INSTALL_ACTION_DEFAULT; | |
| 1113 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1114 | |
| 1115 EXPECT_EQ(POST_INSTALL_ACTION_DEFAULT, result_info.post_install_action); | |
| 1116 } | |
| 1117 | |
| 1118 | |
| 1119 TEST_F(InstallManagerInstallAppUserTest, | |
| 1120 PopulateSuccessfulInstallResultInfo_RebootShouldNotBeOverridden) { | |
| 1121 const SuccessfulInstallAction kSuccessActions[] = { | |
| 1122 SUCCESS_ACTION_DEFAULT, | |
| 1123 SUCCESS_ACTION_EXIT_SILENTLY, | |
| 1124 SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD, | |
| 1125 }; | |
| 1126 | |
| 1127 for (int i = 0; i < arraysize(kSuccessActions); ++i) { | |
| 1128 SetPostInstallActionInManifest(kSuccessActions[i], | |
| 1129 _T("http://foo/bar"), | |
| 1130 true, | |
| 1131 app_); | |
| 1132 | |
| 1133 InstallerResultInfo result_info; | |
| 1134 result_info.type = INSTALLER_RESULT_SUCCESS; | |
| 1135 result_info.post_install_action = POST_INSTALL_ACTION_REBOOT; | |
| 1136 result_info.post_install_launch_command_line = _T("foo.exe"); | |
| 1137 PopulateSuccessfulInstallResultInfo(app_, &result_info); | |
| 1138 | |
| 1139 EXPECT_EQ(POST_INSTALL_ACTION_REBOOT, result_info.post_install_action); | |
| 1140 } | |
| 1141 } | |
| 1142 | |
| 1143 } // namespace omaha | |
| OLD | NEW |