| // Copyright 2008-2009 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ======================================================================== |
| |
| #include "omaha/common/app_util.h" |
| #include "omaha/common/error.h" |
| #include "omaha/common/file.h" |
| #include "omaha/common/path.h" |
| #include "omaha/common/scoped_ptr_address.h" |
| #include "omaha/common/system.h" |
| #include "omaha/common/time.h" |
| #include "omaha/common/utils.h" |
| #include "omaha/common/vistautil.h" |
| #include "omaha/goopdate/config_manager.h" |
| #include "omaha/goopdate/const_goopdate.h" |
| #include "omaha/goopdate/goopdate_utils.h" |
| #include "omaha/goopdate/goopdate_xml_parser.h" |
| #include "omaha/testing/unit_test.h" |
| #include "omaha/worker/application_data.h" |
| #include "omaha/worker/application_manager.h" |
| #include "omaha/worker/job.h" |
| #include "omaha/worker/job_observer_mock.h" |
| #include "omaha/worker/ping.h" |
| |
| namespace omaha { |
| |
| namespace { |
| |
| /* |
| void CreateTestAppData(AppData* app_data) { |
| ASSERT_TRUE(app_data != NULL); |
| app_data->set_version(_T("1.1.1.3")); |
| app_data->set_previous_version(_T("1.0.0.0")); |
| app_data->set_language(_T("abc")); |
| app_data->set_ap(_T("Test ap")); |
| app_data->set_tt_token(_T("Test TT Token")); |
| app_data->set_iid(StringToGuid(_T("{F723495F-8ACF-4746-824d-643741C797B5}"))); |
| app_data->set_brand_code(_T("GOOG")); |
| app_data->set_client_id(_T("someclient")); |
| app_data->set_did_run(AppData::ACTIVE_RUN); |
| app_data->set_install_source(_T("twoclick")); |
| } |
| */ |
| |
| const TCHAR kFooGuid[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}"); |
| const TCHAR kFullFooAppClientKeyPath[] = |
| _T("HKLM\\Software\\Google\\Update\\Clients\\") |
| _T("{D6B08267-B440-4C85-9F79-E195E80D9937}"); |
| const TCHAR kFullFooAppClientStateKeyPath[] = |
| _T("HKLM\\Software\\Google\\Update\\ClientState\\") |
| _T("{D6B08267-B440-4C85-9F79-E195E80D9937}"); |
| const TCHAR kSetupFooV1RelativeLocation[] = |
| _T("unittest_support\\test_foo_v1.0.101.0.msi"); |
| |
| const TCHAR kMsiLogFormat[] = _T("%s.log"); |
| const TCHAR kMsiUninstallArguments[] = _T("/quiet /uninstall %s"); |
| const TCHAR kMsiCommand[] = _T("msiexec"); |
| |
| const TCHAR kJobExecutable[] = _T("cmd.exe"); |
| const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s"); |
| |
| const TCHAR expected_iid_string[] = |
| _T("{BF66411E-8FAC-4E2C-920C-849DF562621C}"); |
| |
| CString CreateUniqueTempDir() { |
| GUID guid(GUID_NULL); |
| EXPECT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid)); |
| CString unique_dir_path = |
| ConcatenatePath(app_util::GetTempDir(), GuidToString(guid)); |
| EXPECT_HRESULT_SUCCEEDED(CreateDir(unique_dir_path, NULL)); |
| return unique_dir_path; |
| } |
| |
| } // namespace |
| |
| class JobTest : public testing::Test { |
| protected: |
| JobTest() : is_machine_(true) {} |
| |
| void SetUp() { |
| // Default to an auto-update job. |
| job_.reset(new Job(true, &ping_)); |
| job_->is_background_ = true; |
| } |
| |
| void set_info(const CompletionInfo& info) { |
| job_->info_ = info; |
| } |
| |
| void set_job_state(JobState job_state) { |
| job_->job_state_ = job_state; |
| } |
| |
| void SetIsInstallJob() { |
| job_->is_update_ = false; |
| job_->is_background_ = false; |
| } |
| |
| HRESULT DoCompleteJob() { |
| return job_->DoCompleteJob(); |
| } |
| |
| HRESULT SendStateChangePing(JobState previous_state) { |
| return job_->SendStateChangePing(previous_state); |
| } |
| |
| void SetUpdateResponseDataArguments(const CString& arguments) { |
| job_->update_response_data_.set_arguments(arguments); |
| } |
| |
| void SetUpdateResponseSuccessAction(SuccessfulInstallAction success_action) { |
| job_->update_response_data_.set_success_action(success_action); |
| } |
| |
| void SetAppData(const AppData& app_data) { |
| job_->set_app_data(app_data); |
| } |
| |
| void set_download_file_name(const CString& download_file) { |
| job_->download_file_name_ = download_file; |
| } |
| |
| HRESULT UpdateRegistry(AppData* data) { |
| return job_->UpdateRegistry(data); |
| } |
| |
| HRESULT UpdateJob() { |
| return job_->UpdateJob(); |
| } |
| |
| HRESULT DeleteJobDownloadDirectory() const { |
| return job_->DeleteJobDownloadDirectory(); |
| } |
| |
| void set_launch_cmd_line(const CString launch_cmd_line) { |
| job_->launch_cmd_line_ = launch_cmd_line; |
| } |
| |
| bool did_launch_cmd_fail() { return job_->did_launch_cmd_fail_; } |
| void set_did_launch_cmd_fail(bool did_launch_cmd_fail) { |
| job_->did_launch_cmd_fail_ = did_launch_cmd_fail; |
| } |
| |
| scoped_ptr<Job> job_; |
| Ping ping_; |
| bool is_machine_; |
| }; |
| |
| // Does not override registry hives because it would not affect the installer. |
| class JobInstallFooTest : public JobTest { |
| protected: |
| virtual void SetUp() { |
| JobTest::SetUp(); |
| |
| foo_installer_path_ = ConcatenatePath(app_util::GetCurrentModuleDirectory(), |
| kSetupFooV1RelativeLocation); |
| ASSERT_TRUE(File::Exists(foo_installer_path_)); |
| |
| foo_installer_log_path_.Format(kMsiLogFormat, foo_installer_path_); |
| |
| ASSERT_HRESULT_SUCCEEDED(File::Remove(foo_installer_log_path_)); |
| ASSERT_FALSE(File::Exists(foo_installer_log_path_)); |
| |
| RegKey::DeleteKey(kFullFooAppClientKeyPath); |
| ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); |
| RegKey::DeleteKey(kFullFooAppClientStateKeyPath); |
| ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); |
| } |
| |
| virtual void TearDown() { |
| RegKey::DeleteKey(kFullFooAppClientKeyPath); |
| RegKey::DeleteKey(kFullFooAppClientStateKeyPath); |
| } |
| |
| AppData PopulateFooAppData() { |
| AppData app_data(StringToGuid(kFooGuid), is_machine_); |
| app_data.set_display_name(_T("Foo")); |
| app_data.set_language(_T("en")); |
| app_data.set_ap(_T("test_ap")); |
| app_data.set_iid(StringToGuid(expected_iid_string)); |
| app_data.set_brand_code(_T("GOOG")); |
| app_data.set_client_id(_T("_some_partner")); |
| app_data.set_browser_type(BROWSER_IE); |
| app_data.set_usage_stats_enable(TRISTATE_TRUE); |
| return app_data; |
| } |
| |
| // Verifies the values that are written to ClientState before installing. |
| // Assumes the is Foo. |
| void VerifyFooClientStateValuesWrittenBeforeInstall(bool is_first_install) { |
| CString str_value; |
| DWORD value; |
| |
| if (is_first_install) { |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrandCode, |
| &str_value)); |
| EXPECT_STREQ(_T("GOOG"), str_value); |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueClientId, |
| &str_value)); |
| EXPECT_STREQ(_T("_some_partner"), str_value); |
| const uint32 now = Time64ToInt32(GetCurrent100NSTime()); |
| DWORD install_time(0); |
| EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueInstallTimeSec, |
| &install_time)); |
| EXPECT_GE(now, install_time); |
| EXPECT_GE(static_cast<uint32>(500), now - install_time); |
| } else { |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrandCode, |
| &str_value)); |
| EXPECT_STREQ(_T("g00g"), str_value); |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| kRegValueClientId)); |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| kRegValueInstallTimeSec)); |
| } |
| |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueAdditionalParams, |
| &str_value)); |
| EXPECT_STREQ(_T("test_ap"), str_value); |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrowser, |
| &value)); |
| EXPECT_EQ(BROWSER_IE, value); |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| _T("usagestats"), |
| &value)); |
| EXPECT_EQ(TRISTATE_TRUE, value); |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLanguage, |
| &str_value)); |
| EXPECT_STREQ(_T("en"), str_value); |
| } |
| |
| void VerifyFooClientStateValuesWrittenBeforeInstallNotPresent( |
| bool is_brand_code_present) { |
| CString str_value; |
| DWORD value; |
| |
| HRESULT hr = RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrandCode, |
| &str_value); |
| if (is_brand_code_present) { |
| EXPECT_HRESULT_SUCCEEDED(hr); |
| } else { |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr); |
| } |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueClientId, |
| &str_value)); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrowser, |
| &value)); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| _T("usagestats"), |
| &value)); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLanguage, |
| &str_value)); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueAdditionalParams, |
| &str_value)); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueTTToken, |
| &str_value)); |
| } |
| |
| // Verifies the values that are written to ClientState after successfully |
| // installing. Assumes the is Foo. |
| void VerifyFooClientStateValuesWrittenAfterSuccessfulInstall() { |
| CString str_value; |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueProductVersion, |
| &str_value)); |
| EXPECT_STREQ(_T("1.0.101.0"), str_value); |
| // TODO(omaha): Verify language. Requires changing the MSI. Make sure the |
| // language the MSI writes is different than in PopulateFooAppData(). |
| // When we do this, make sure we also have a test where the app does not |
| // write lang in Client to verify that the ClientState value is not erased. |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| kRegValueInstallationId, |
| &str_value)); |
| EXPECT_STREQ(expected_iid_string, str_value); |
| } |
| |
| void Install_MsiInstallerSucceeds(bool is_update, |
| bool is_first_install, |
| bool is_offline); |
| void Install_InstallerFailed_WhenNoExistingPreInstallData(bool is_update); |
| void Install_InstallerFailed_WhenExistingPreInstallData(bool is_update); |
| |
| CString foo_installer_path_; |
| CString foo_installer_log_path_; |
| }; |
| |
| // TODO(omaha): Test all methods of Job |
| |
| // No attempt is made to delete it the directory in this case. |
| TEST_F(JobTest, DeleteJobDownloadDirectory_Omaha_Test) { |
| const TCHAR* kNnonExistantDir = _T("testdirfoo"); |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| |
| set_info(info); |
| set_download_file_name(ConcatenatePath(kNnonExistantDir, _T("foo.msi"))); |
| |
| AppData app_data; |
| app_data.set_app_guid(kGoopdateGuid); |
| SetAppData(app_data); |
| |
| ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory()); |
| } |
| |
| // The download file name is not set and no attempt to delete it is made for |
| // update checks only. |
| TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdateCheckOnly) { |
| job_.reset(new Job(true, &ping_)); |
| job_->set_is_update_check_only(true); |
| |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| |
| set_info(info); |
| |
| AppData app_data; |
| app_data.set_app_guid( |
| StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}"))); |
| SetAppData(app_data); |
| |
| ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory()); |
| } |
| |
| TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdate) { |
| job_.reset(new Job(true, &ping_)); |
| |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| set_info(info); |
| const CString destination_path = CreateUniqueTempDir(); |
| set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi"))); |
| |
| AppData app_data; |
| app_data.set_app_guid( |
| StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}"))); |
| SetAppData(app_data); |
| |
| ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory()); |
| ASSERT_FALSE(File::Exists(destination_path)); |
| } |
| |
| TEST_F(JobTest, DeleteJobDownloadDirectory_Success) { |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| set_info(info); |
| const CString destination_path = CreateUniqueTempDir(); |
| set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi"))); |
| |
| AppData app_data; |
| app_data.set_app_guid( |
| StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}"))); |
| SetAppData(app_data); |
| |
| ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory()); |
| ASSERT_FALSE(File::Exists(destination_path)); |
| } |
| |
| TEST_F(JobTest, SendStateChangePing) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| AppManager app_manager(is_machine_); |
| AppData app_data(StringToGuid(_T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}")), |
| is_machine_); |
| |
| app_data.set_language(_T("abc")); |
| app_data.set_ap(_T("Test ap")); |
| app_data.set_tt_token(_T("Test TT Token")); |
| app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}"))); |
| app_data.set_brand_code(_T("GOOG")); |
| app_data.set_client_id(_T("otherclient")); |
| app_data.set_display_name(_T("UnitTest")); |
| app_data.set_browser_type(BROWSER_DEFAULT); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_INSTALLERSTARTED); |
| ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_DOWNLOADCOMPLETED)); |
| |
| CompletionInfo info(COMPLETION_ERROR, 123, _T("")); |
| |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot); |
| OverrideRegistryHives(kRegistryHiveOverrideRoot); |
| CString app_goopdate_key_name = goopdate_utils::GetAppClientsKey( |
| is_machine_, |
| GOOPDATE_APP_ID); |
| |
| RegKey goopdate_key; |
| EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(app_goopdate_key_name, |
| kRegValueProductVersion, |
| _T("1.2.3.4"))); |
| job_->NotifyCompleted(info); |
| |
| RestoreRegistryHives(); |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot); |
| ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_INSTALLERSTARTED)); |
| } |
| |
| TEST_F(JobTest, UpdateRegistry) { |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| |
| CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}"); |
| CString expected_version = _T("1.3.3.3"); |
| CString previous_version = _T("1.0.0.0"); |
| CString expected_lang = _T("abc"); |
| CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid); |
| ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path)); |
| ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path, |
| kRegValueProductVersion, |
| expected_version)); |
| ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path, |
| kRegValueLanguage, |
| expected_lang)); |
| |
| AppManager app_manager(is_machine_); |
| AppData app_data(StringToGuid(app_guid), is_machine_); |
| app_data.set_version(expected_version); |
| app_data.set_previous_version(previous_version); |
| app_data.set_language(expected_lang); |
| app_data.set_ap(_T("Test ap")); |
| app_data.set_tt_token(_T("Test TT Token")); |
| app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}"))); |
| app_data.set_brand_code(_T("GOOG")); |
| app_data.set_client_id(_T("otherclient")); |
| app_data.set_display_name(_T("UnitTest")); |
| app_data.set_browser_type(BROWSER_DEFAULT); |
| app_data.set_install_source(_T("install source")); |
| job_->set_app_data(app_data); |
| set_job_state(JOBSTATE_COMPLETED); |
| |
| // Call the test method. |
| AppData new_app_data; |
| ASSERT_SUCCEEDED(UpdateRegistry(&new_app_data)); |
| |
| // Check the results. |
| reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid); |
| ASSERT_SUCCEEDED(RegKey::HasKey(reg_key_path)); |
| |
| CString actual_previous_version; |
| ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path, |
| kRegValueProductVersion, |
| &actual_previous_version)); |
| CString actual_lang; |
| ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path, |
| kRegValueLanguage, |
| &actual_lang)); |
| |
| // The client state registry should have been updated. |
| EXPECT_STREQ(expected_version, actual_previous_version); |
| EXPECT_STREQ(expected_lang, actual_lang); |
| |
| // The job's previous version should not have changed. |
| EXPECT_STREQ(expected_version, job_->app_data().version()); |
| EXPECT_STREQ(previous_version, job_->app_data().previous_version()); |
| |
| // new_app_data's previous_version should have been updated. |
| EXPECT_STREQ(expected_version, new_app_data.version()); |
| EXPECT_STREQ(expected_version, new_app_data.previous_version()); |
| |
| RestoreRegistryHives(); |
| ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| TEST_F(JobTest, UpdateJob) { |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| |
| CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}"); |
| CString expected_version = _T("1.3.3.3"); |
| CString previous_version = _T("1.0.0.0"); |
| CString expected_lang = _T("abc"); |
| CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid); |
| ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path)); |
| ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path, |
| kRegValueProductVersion, |
| expected_version)); |
| ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path, |
| kRegValueLanguage, |
| expected_lang)); |
| |
| AppManager app_manager(is_machine_); |
| AppData app_data(StringToGuid(app_guid), is_machine_); |
| app_data.set_version(_T("4.5.6.6")); |
| app_data.set_previous_version(previous_version); |
| app_data.set_language(expected_lang); |
| app_data.set_ap(_T("Test ap")); |
| app_data.set_tt_token(_T("Test TT Token")); |
| app_data.set_iid( |
| StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}"))); |
| app_data.set_brand_code(_T("GOOG")); |
| app_data.set_client_id(_T("otherclient")); |
| app_data.set_display_name(_T("UnitTest")); |
| app_data.set_browser_type(BROWSER_DEFAULT); |
| app_data.set_install_source(_T("install source")); |
| job_->set_app_data(app_data); |
| set_job_state(JOBSTATE_COMPLETED); |
| |
| // Call the test method. |
| ASSERT_SUCCEEDED(UpdateJob()); |
| |
| // Check the results. |
| reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid); |
| CString version; |
| EXPECT_HRESULT_FAILED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueProductVersion, |
| &version)); |
| |
| // The job's information should have been changed. |
| EXPECT_STREQ(expected_version, job_->app_data().version()); |
| EXPECT_STREQ(previous_version, job_->app_data().previous_version()); |
| |
| RestoreRegistryHives(); |
| ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| |
| // The use of kGoogleUpdateAppId is the key to this test. |
| // Overrides the registry hives. |
| TEST_F(JobTest, Install_UpdateOmahaSucceeds) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| |
| CString arguments; |
| arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi")); |
| |
| AppData app_data(kGoopdateGuid, is_machine_); |
| job_->set_download_file_name(kJobExecutable); |
| job_->set_app_data(app_data); |
| SetUpdateResponseDataArguments(arguments); |
| |
| CString expected_version(_T("0.9.69.5")); |
| CString expected_lang(_T("en")); |
| |
| // Because we don't actually run the Omaha installer, we need to make sure |
| // its Clients key and pv value exist to avoid an error. |
| ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENTS_GOOPDATE)); |
| ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE)); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE, |
| kRegValueProductVersion, |
| expected_version)); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE, |
| kRegValueLanguage, |
| expected_lang)); |
| |
| ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE)); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_HRESULT_SUCCEEDED(job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status); |
| EXPECT_EQ(S_OK, job_->info().error_code); |
| // The user never sees this, but it is odd we put this text in the structure. |
| EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text); |
| |
| EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE)); |
| EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE)); |
| |
| CString version; |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueProductVersion, |
| &version)); |
| EXPECT_STREQ(expected_version, version); |
| |
| RestoreRegistryHives(); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| // Update values should not be changed because we do not know whether |
| // self-updates have succeeded yet. |
| // Successful update and check values are not changed either. |
| TEST_F(JobTest, Install_SuccessfulOmahaUpdateDoesNotClearUpdateAvailableStats) { |
| is_machine_ = false; |
| |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| |
| CString arguments; |
| arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi")); |
| |
| AppData app_data(kGoopdateGuid, is_machine_); |
| job_->set_download_file_name(kJobExecutable); |
| job_->set_app_data(app_data); |
| SetUpdateResponseDataArguments(arguments); |
| |
| CString expected_version(_T("0.9.69.5")); |
| CString expected_lang(_T("en")); |
| |
| // Because we don't actually run the Omaha installer, we need to make sure |
| // its Clients key and pv value exist to avoid an error. |
| ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE)); |
| ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE, |
| kRegValueProductVersion, |
| expected_version)); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE, |
| kRegValueLanguage, |
| expected_lang)); |
| |
| // Set update values so we can verify they are not modified or deleted. |
| EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| _T("UpdateAvailableCount"), |
| static_cast<DWORD>(123456))); |
| EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| _T("UpdateAvailableSince"), |
| static_cast<DWORD64>(9876543210))); |
| const DWORD kExistingUpdateValues = 0x70123456; |
| EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueLastSuccessfulCheckSec, |
| kExistingUpdateValues)); |
| EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueLastUpdateTimeSec, |
| kExistingUpdateValues)); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_HRESULT_SUCCEEDED(job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status); |
| EXPECT_EQ(S_OK, job_->info().error_code); |
| // The user never sees this, but it is odd we put this text in the structure. |
| EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text); |
| |
| EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); |
| EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE)); |
| |
| CString version; |
| EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueProductVersion, |
| &version)); |
| EXPECT_STREQ(expected_version, version); |
| |
| DWORD update_available_count(0); |
| EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| _T("UpdateAvailableCount"), |
| &update_available_count)); |
| EXPECT_EQ(123456, update_available_count); |
| |
| DWORD64 update_available_since_time(0); |
| EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| _T("UpdateAvailableSince"), |
| &update_available_since_time)); |
| EXPECT_EQ(9876543210, update_available_since_time); |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueLastSuccessfulCheckSec)); |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE, |
| kRegValueLastUpdateTimeSec)); |
| |
| RestoreRegistryHives(); |
| ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| TEST_F(JobTest, GetInstallerData) { |
| UpdateResponses responses; |
| CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(), |
| _T("server_manifest.xml"))); |
| GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}")); |
| |
| const TCHAR* kVerboseLog = _T("\n {\n \"distribution\": {\n ") |
| _T("\"verbose_logging\": true\n }\n }\n "); |
| const TCHAR* kSkipFirstRun = _T("{\n \"distribution\": {\n \"") |
| _T("skip_first_run_ui\": true,\n }\n }\n "); |
| CString skip_first_run_encoded; |
| EXPECT_SUCCEEDED(WideStringToUtf8UrlEncodedString(kSkipFirstRun, |
| &skip_first_run_encoded)); |
| |
| ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses)); |
| UpdateResponseData response_data = responses[guid].update_response_data(); |
| job_->set_update_response_data(response_data); |
| |
| // Only set install_data_index to a valid value. |
| AppData app_data1(guid, is_machine_); |
| app_data1.set_install_data_index(_T("verboselogging")); |
| job_->set_app_data(app_data1); |
| |
| CString installer_data1; |
| EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data1)); |
| EXPECT_STREQ(kVerboseLog, installer_data1); |
| |
| // Set both installer_data and install_data_index to valid values. |
| AppData app_data2(guid, is_machine_); |
| app_data2.set_encoded_installer_data(skip_first_run_encoded); |
| app_data2.set_install_data_index(_T("verboselogging")); |
| job_->set_app_data(app_data2); |
| |
| CString installer_data2; |
| EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data2)); |
| EXPECT_STREQ(kSkipFirstRun, installer_data2); |
| |
| // Set installer_data to invalid value, and install_data_index to valid value. |
| AppData app_data3(guid, is_machine_); |
| app_data3.set_encoded_installer_data(_T("%20%20")); |
| app_data3.set_install_data_index(_T("verboselogging")); |
| job_->set_app_data(app_data3); |
| |
| CString installer_data3; |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS, |
| job_->GetInstallerData(&installer_data3)); |
| |
| // Set installer_data to valid value, and install_data_index to invalid value. |
| AppData app_data4(guid, is_machine_); |
| app_data4.set_encoded_installer_data(skip_first_run_encoded); |
| app_data4.set_install_data_index(_T("foobar")); |
| job_->set_app_data(app_data4); |
| |
| CString installer_data4; |
| EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data4)); |
| EXPECT_STREQ(kSkipFirstRun, installer_data4); |
| |
| // Set only install_data_index to invalid value. |
| AppData app_data5(guid, is_machine_); |
| app_data5.set_install_data_index(_T("foobar")); |
| job_->set_app_data(app_data5); |
| |
| CString installer_data5; |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, |
| job_->GetInstallerData(&installer_data5)); |
| |
| // Set neither installer_data nor install_data_index. |
| AppData app_data6(guid, is_machine_); |
| job_->set_app_data(app_data6); |
| |
| CString installer_data6; |
| EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data6)); |
| EXPECT_TRUE(installer_data6.IsEmpty()); |
| } |
| |
| // It would be nice if the Foo installer actually used the installer data as a |
| // way to verify the data file is passed correctly. Alternatively, we could mock |
| // the installer execution. |
| TEST_F(JobInstallFooTest, InstallerData_ValidIndex) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| UpdateResponses responses; |
| CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(), |
| _T("server_manifest.xml"))); |
| GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}")); |
| |
| ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses)); |
| UpdateResponseData response_data = responses[guid].update_response_data(); |
| job_->set_update_response_data(response_data); |
| |
| AppData app_data(PopulateFooAppData()); |
| app_data.set_install_data_index(_T("verboselogging")); |
| job_->set_download_file_name(foo_installer_path_); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_HRESULT_SUCCEEDED(job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status); |
| EXPECT_EQ(S_OK, job_->info().error_code); |
| EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text); |
| } |
| |
| // Set installer_data to invalid value, and install_data_index to valid value. |
| TEST_F(JobInstallFooTest, InstallerData_InvalidData) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| AppData app_data(PopulateFooAppData()); |
| app_data.set_encoded_installer_data(_T("%20%20")); |
| app_data.set_install_data_index(_T("verboselogging")); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS, job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_ERROR, job_->info().status); |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS, |
| job_->info().error_code); |
| EXPECT_STREQ( |
| _T("Installation failed. Please try again. Error code = 0x8004090a"), |
| job_->info().text); |
| } |
| |
| TEST_F(JobInstallFooTest, InstallerData_NonExistentIndex) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| AppData app_data(PopulateFooAppData()); |
| app_data.set_install_data_index(_T("foobar")); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_ERROR, job_->info().status); |
| EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->info().error_code); |
| EXPECT_STREQ( |
| _T("Installation failed. Please try again. Error code = 0x80040909"), |
| job_->info().text); |
| } |
| |
| /* |
| // TODO(omaha): Adapt into a test for SendStateChangePing by mocking ping. |
| TEST_F(JobTest, BuildPingRequestFromJob_PopulatesAppRequest) { |
| const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}"); |
| AppData app_data(StringToGuid(kGuid), true); |
| CreateTestAppData(&app_data); |
| job_->set_app_data(app_data); |
| set_job_state(JOBSTATE_COMPLETED); |
| |
| CompletionInfo info(COMPLETION_INSTALLER_ERROR_MSI, 0x12345678, _T("foo")); |
| set_info(info); |
| |
| Request req(true); |
| BuildPingRequestFromJob(&req); |
| ASSERT_EQ(1, req.get_app_count()); |
| |
| const AppRequest* app_request = req.GetApp(StringToGuid(kGuid)); |
| EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"), |
| GuidToString(app_request->guid())); |
| EXPECT_EQ(_T("1.1.1.3"), app_request->version()); |
| EXPECT_EQ(_T("abc"), app_request->language()); |
| EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request->active()); |
| EXPECT_TRUE(app_request->tag().IsEmpty()); |
| EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"), |
| GuidToString(app_request->installation_id())); |
| EXPECT_EQ(_T("GOOG"), app_request->brand_code()); |
| EXPECT_EQ(_T("someclient"), app_request->client_id()); |
| EXPECT_EQ(_T("twoclick"), app_request->install_source()); |
| |
| ASSERT_TRUE(app_request->events_end() == ++app_request->events_begin()); |
| const AppEvent* app_event = *app_request->events_begin(); |
| EXPECT_EQ(AppEvent::EVENT_UPDATE_COMPLETE, app_event->event_type()); |
| EXPECT_EQ(AppEvent::EVENT_RESULT_INSTALLER_ERROR_MSI, |
| app_event->event_result()); |
| EXPECT_EQ(0x12345678, app_event->error_code()); |
| EXPECT_EQ(0, app_event->extra_code1()); |
| EXPECT_EQ(_T("1.0.0.0"), app_event->previous_version()); |
| } |
| |
| // TODO(omaha): Adapt into a test for CreateRequestFromProducts |
| TEST_F(JobTest, BuildRequest_PopulatesAppRequest) { |
| const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}"); |
| AppData app_data(StringToGuid(kGuid), true); |
| CreateTestAppData(&app_data); |
| job_->set_app_data(app_data); |
| |
| Request req(true); |
| ASSERT_SUCCEEDED(job_->BuildRequest(&req)); |
| ASSERT_EQ(1, req.get_app_count()); |
| |
| const AppRequest* app_request = req.GetApp(StringToGuid(kGuid)); |
| EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"), |
| GuidToString(app_request->guid())); |
| EXPECT_EQ(_T("1.1.1.3"), app_request->version()); |
| EXPECT_EQ(_T("abc"), app_request->language()); |
| EXPECT_EQ(AppData::ACTIVE_RUN, app_request->active()); |
| EXPECT_EQ(_T("Test ap"), app_request->tag()); |
| EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"), |
| GuidToString(app_request->installation_id())); |
| EXPECT_EQ(_T("GOOG"), app_request->brand_code()); |
| EXPECT_EQ(_T("someclient"), app_request->client_id()); |
| EXPECT_EQ(_T("twoclick"), app_request->install_source()); |
| } |
| |
| // TODO(omaha): Move to some other test file. |
| TEST(RequestTest, TestInitialized) { |
| AppRequest app_request; |
| EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.guid())); |
| EXPECT_TRUE(app_request.version().IsEmpty()); |
| EXPECT_TRUE(app_request.language().IsEmpty()); |
| EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request.active()); |
| EXPECT_TRUE(app_request.tag().IsEmpty()); |
| EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.installation_id())); |
| EXPECT_TRUE(app_request.brand_code().IsEmpty()); |
| EXPECT_TRUE(app_request.client_id().IsEmpty()); |
| EXPECT_TRUE(app_request.install_source().IsEmpty()); |
| } |
| */ |
| |
| void JobInstallFooTest::Install_MsiInstallerSucceeds(bool is_update, |
| bool is_first_install, |
| bool is_offline) { |
| ASSERT_TRUE(!is_update || !is_offline); |
| |
| const DWORD kExistingUpdateValues = 0x70123456; |
| |
| // TODO(omaha): Use UserFoo instead, change is_machine in the base class, |
| // and remove all IsUserAdmin checks. |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| #ifdef _DEBUG |
| if (!is_update) { |
| // Event::WriteEvent() expects Omaha's version to exist. |
| // Write it if it doesn't exist. |
| ConfigManager& config_mgr = *ConfigManager::Instance(); |
| CString key_name = config_mgr.registry_clients_goopdate(is_machine_); |
| if (!RegKey::HasValue(key_name, kRegValueLanguage)) { |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueLanguage, _T("it"))); |
| } |
| if (!RegKey::HasValue(key_name, kRegValueProductVersion)) { |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.0.0"))); |
| } |
| } |
| #endif |
| |
| if (!is_update) { |
| SetIsInstallJob(); |
| } |
| |
| if (!is_first_install) { |
| // Make it appear to Omaha that Foo was already installed. This does not |
| // affect the installer. |
| EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueBrandCode, |
| _T("g00g"))); |
| |
| // Set update available stats so can verify they are deleted. |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableCount"), |
| static_cast<DWORD>(123456))); |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableSince"), |
| static_cast<DWORD64>(9876543210))); |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec, |
| kExistingUpdateValues)); |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec, |
| kExistingUpdateValues)); |
| } |
| |
| job_->set_is_offline(is_offline); |
| |
| AppData app_data(PopulateFooAppData()); |
| job_->set_download_file_name(foo_installer_path_); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_HRESULT_SUCCEEDED(job_->Install()); |
| const uint32 now = Time64ToInt32(GetCurrent100NSTime()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status); |
| EXPECT_EQ(S_OK, job_->info().error_code); |
| EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text); |
| |
| EXPECT_TRUE(File::Exists(foo_installer_log_path_)); |
| |
| EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath)); |
| EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); |
| |
| if (is_update) { |
| VerifyFooClientStateValuesWrittenBeforeInstallNotPresent(!is_first_install); |
| } else { |
| VerifyFooClientStateValuesWrittenBeforeInstall(is_first_install); |
| } |
| VerifyFooClientStateValuesWrittenAfterSuccessfulInstall(); |
| |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableCount"))); |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableSince"))); |
| if (is_update) { |
| // Verify update values updated. |
| const uint32 last_check_sec = |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec); |
| EXPECT_NE(kExistingUpdateValues, last_check_sec); |
| EXPECT_GE(now, last_check_sec); |
| EXPECT_GE(static_cast<uint32>(200), now - last_check_sec); |
| |
| const uint32 last_update_sec = GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec); |
| EXPECT_NE(kExistingUpdateValues, last_update_sec); |
| EXPECT_GE(now, last_update_sec); |
| EXPECT_GE(static_cast<uint32>(200), now - last_update_sec); |
| } else { |
| // LastSuccessfulCheckSec is written for online installs but never cleared. |
| if (!is_offline) { |
| const uint32 last_check_sec = |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec); |
| EXPECT_NE(kExistingUpdateValues, last_check_sec); |
| EXPECT_GE(now, last_check_sec); |
| EXPECT_GE(static_cast<uint32>(200), now - last_check_sec); |
| } else if (!is_first_install) { |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec)); |
| } else { |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec)); |
| } |
| |
| // kRegValueLastUpdateTimeSec is never written for installs. |
| if (!is_first_install) { |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec)); |
| } else { |
| EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec)); |
| } |
| } |
| |
| CString uninstall_arguments; |
| uninstall_arguments.Format(kMsiUninstallArguments, foo_installer_path_); |
| EXPECT_HRESULT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand, |
| uninstall_arguments, |
| NULL, |
| NULL)); |
| } |
| |
| TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Online) { |
| Install_MsiInstallerSucceeds(false, true, false); |
| } |
| |
| TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Online) { |
| Install_MsiInstallerSucceeds(false, false, false); |
| } |
| |
| TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Offline) { |
| Install_MsiInstallerSucceeds(false, true, true); |
| } |
| |
| TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Offline) { |
| Install_MsiInstallerSucceeds(false, false, true); |
| } |
| |
| TEST_F(JobInstallFooTest, |
| Install_MsiInstallerSucceeds_UpdateWhenNoExistingPreInstallData) { |
| // AppManager::ClearUpdateAvailableStats() asserts that key open succeeds. |
| EXPECT_SUCCEEDED(RegKey::CreateKey(kFullFooAppClientStateKeyPath)); |
| Install_MsiInstallerSucceeds(true, true, false); |
| } |
| |
| TEST_F(JobInstallFooTest, |
| Install_MsiInstallerSucceeds_UpdateWhenExistingPreInstallData) { |
| Install_MsiInstallerSucceeds(true, false, false); |
| } |
| |
| |
| void JobInstallFooTest::Install_InstallerFailed_WhenNoExistingPreInstallData( |
| bool is_update) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| if (!is_update) { |
| SetIsInstallJob(); |
| } |
| |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| #ifdef _DEBUG |
| // Event::WriteEvent() expects Omaha's language and version to exist. |
| ConfigManager& config_mgr = *ConfigManager::Instance(); |
| CString key_name = config_mgr.registry_clients_goopdate(is_machine_); |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueLanguage, _T("it"))); |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3"))); |
| #endif |
| |
| AppData app_data(PopulateFooAppData()); |
| job_->set_download_file_name(_T("DoesNotExist.exe")); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_ERROR, job_->info().status); |
| EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code); |
| EXPECT_STREQ(_T("The installer failed to start."), job_->info().text); |
| |
| EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); |
| EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath)); |
| |
| // TODO(omaha): Install the job successfully and verify that the brand data |
| // is replaced by the successful install. |
| |
| RestoreRegistryHives(); |
| ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| // Overrides the registry hives. |
| TEST_F(JobInstallFooTest, |
| Install_InstallerFailedFirstInstall_WhenNoExistingPreInstallData) { |
| Install_InstallerFailed_WhenNoExistingPreInstallData(false); |
| } |
| |
| TEST_F(JobInstallFooTest, |
| Install_InstallerFailedUpdate_WhenNoExistingPreInstallData) { |
| Install_InstallerFailed_WhenNoExistingPreInstallData(true); |
| } |
| |
| void JobInstallFooTest::Install_InstallerFailed_WhenExistingPreInstallData( |
| bool is_update) { |
| if (!vista_util::IsUserAdmin()) { |
| std::wcout << _T("\tTest did not run because the user is not an admin.") |
| << std::endl; |
| return; |
| } |
| |
| if (!is_update) { |
| SetIsInstallJob(); |
| } |
| |
| RegKey::DeleteKey(kRegistryHiveOverrideRoot, true); |
| OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot); |
| |
| #ifdef _DEBUG |
| // Event::WriteEvent() expects Omaha's language and version to exist. |
| ConfigManager& config_mgr = *ConfigManager::Instance(); |
| CString key_name = config_mgr.registry_clients_goopdate(is_machine_); |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueLanguage, _T("it"))); |
| EXPECT_HRESULT_SUCCEEDED( |
| RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3"))); |
| #endif |
| |
| // Prepopulate data for this app in the ClientState registry |
| EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueProductVersion, |
| _T("0.1.2.3"))); |
| |
| // Set update available stats so can verify they are not modified or deleted. |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableCount"), |
| static_cast<DWORD>(123456))); |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableSince"), |
| static_cast<DWORD64>(9876543210))); |
| const DWORD kExistingUpdateValues = 0x70123456; |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec, |
| kExistingUpdateValues)); |
| EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec, |
| kExistingUpdateValues)); |
| |
| AppData app_data(PopulateFooAppData()); |
| job_->set_download_file_name(_T("DoesNotExist.exe")); |
| job_->set_app_data(app_data); |
| |
| set_job_state(JOBSTATE_DOWNLOADCOMPLETED); |
| EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install()); |
| |
| EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state()); |
| |
| EXPECT_EQ(COMPLETION_ERROR, job_->info().status); |
| EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code); |
| EXPECT_STREQ(_T("The installer failed to start."), job_->info().text); |
| |
| EXPECT_EQ(is_update, RegKey::HasKey(kFullFooAppClientStateKeyPath)); |
| EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath)); |
| |
| // When an update fails, data remains. When an install fails, the entire |
| // ClientState key is deleted as verified above. |
| if (is_update) { |
| DWORD update_available_count(0); |
| EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableCount"), |
| &update_available_count)); |
| EXPECT_EQ(123456, update_available_count); |
| |
| DWORD64 update_available_since_time(0); |
| EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath, |
| _T("UpdateAvailableSince"), |
| &update_available_since_time)); |
| EXPECT_EQ(9876543210, update_available_since_time); |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastSuccessfulCheckSec)); |
| EXPECT_EQ(kExistingUpdateValues, |
| GetDwordValue(kFullFooAppClientStateKeyPath, |
| kRegValueLastUpdateTimeSec)); |
| } |
| |
| RestoreRegistryHives(); |
| ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true)); |
| } |
| |
| TEST_F(JobInstallFooTest, |
| Install_InstallerFailedFirstInstall_WhenExistingPreInstallData) { |
| Install_InstallerFailed_WhenExistingPreInstallData(false); |
| } |
| |
| TEST_F(JobInstallFooTest, |
| Install_InstallerFailedUpdate_WhenExistingPreInstallData) { |
| Install_InstallerFailed_WhenExistingPreInstallData(true); |
| } |
| |
| TEST_F(JobTest, LaunchCmdLine_EmptyCommand) { |
| SetIsInstallJob(); |
| EXPECT_SUCCEEDED(job_->LaunchCmdLine()); |
| EXPECT_FALSE(did_launch_cmd_fail()); |
| } |
| |
| TEST_F(JobTest, LaunchCmdLine_LaunchFails) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("no_such_file.exe")); |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), job_->LaunchCmdLine()); |
| EXPECT_TRUE(did_launch_cmd_fail()); |
| } |
| |
| TEST_F(JobTest, LaunchCmdLine_Succeeds) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("cmd /c")); |
| EXPECT_SUCCEEDED(job_->LaunchCmdLine()); |
| EXPECT_FALSE(did_launch_cmd_fail()); |
| } |
| |
| // LaunchCmdLine should not be called for update jobs. |
| TEST_F(JobTest, LaunchCmdLine_IsUpdateJob) { |
| ExpectAsserts expect_asserts; |
| set_launch_cmd_line(_T("cmd /c")); |
| EXPECT_SUCCEEDED(job_->LaunchCmdLine()); |
| EXPECT_FALSE(did_launch_cmd_fail()); |
| } |
| |
| class JobDoCompleteJobJobSuccessTest : public JobTest { |
| protected: |
| virtual void SetUp() { |
| JobTest::SetUp(); |
| |
| destination_path_ = CreateUniqueTempDir(); |
| set_download_file_name(ConcatenatePath(destination_path_, _T("foo.msi"))); |
| job_->set_job_observer(&job_observer_); |
| |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| set_info(info); |
| } |
| |
| CString destination_path_; |
| JobObserverMock job_observer_; |
| }; |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, DefaultSuccessAction) { |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| |
| EXPECT_FALSE(File::Exists(destination_path_)); |
| } |
| |
| // download_file_name_ is not set. No assert indicates that |
| // DeleteJobDownloadDirectory is not called in error cases. |
| TEST_F(JobTest, DefaultSuccessAction_Omaha) { |
| JobObserverMock job_observer; |
| job_->set_job_observer(&job_observer); |
| |
| CompletionInfo info(COMPLETION_SUCCESS, 0, _T("")); |
| set_info(info); |
| |
| AppData app_data; |
| app_data.set_app_guid(kGoopdateGuid); |
| SetAppData(app_data); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer.completion_code); |
| EXPECT_TRUE(job_observer.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| DefaultSuccessAction_LaunchCmdNotFailed) { |
| SetIsInstallJob(); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| DefaultSuccessAction_LaunchCmdFailed) { |
| SetIsInstallJob(); |
| set_did_launch_cmd_fail(true); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| SuccessActionExitSilently_NoLaunchCmd) { |
| SetIsInstallJob(); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| SuccessActionExitSilently_LaunchCmdNotFailed) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("cmd /c")); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| SuccessActionExitSilently_LaunchCmdFailed) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("cmd /c")); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY); |
| set_did_launch_cmd_fail(true); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| SuccessActionExitSilentlyOnCmd_NoLaunchCmd) { |
| SetIsInstallJob(); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| SuccessActionExitSilentlyOnCmd_CmdNotFailed) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("cmd /c")); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| TEST_F(JobDoCompleteJobJobSuccessTest, |
| DefaultSuccessActionOnCmd_LaunchCmdFailed) { |
| SetIsInstallJob(); |
| set_launch_cmd_line(_T("cmd /c")); |
| SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD); |
| set_did_launch_cmd_fail(true); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code); |
| EXPECT_TRUE(job_observer_.completion_text.IsEmpty()); |
| EXPECT_EQ(0, job_observer_.completion_error_code); |
| } |
| |
| // download_file_name_ is not set. No assert indicates that |
| // DeleteJobDownloadDirectory is not called in error cases. |
| TEST_F(JobTest, DoCompleteJob_JobError) { |
| JobObserverMock job_observer_; |
| job_->set_job_observer(&job_observer_); |
| CompletionInfo info(COMPLETION_ERROR, static_cast<DWORD>(E_FAIL), _T("blah")); |
| set_info(info); |
| |
| EXPECT_SUCCEEDED(DoCompleteJob()); |
| |
| EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code); |
| EXPECT_STREQ(_T("blah"), job_observer_.completion_text); |
| EXPECT_EQ(E_FAIL, job_observer_.completion_error_code); |
| } |
| |
| } // namespace omaha |