| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/command_line.h" |
| 6 #include "base/file_path.h" |
| 7 #include "base/logging.h" |
| 8 #include "base/ref_counted.h" |
| 9 #include "base/version.h" |
| 10 #include "chrome/common/chrome_constants.h" |
| 11 #include "chrome/installer/util/channel_info.h" |
| 12 #include "chrome/installer/util/helper.h" |
| 13 #include "chrome/installer/util/installation_state.h" |
| 14 #include "chrome/installer/util/installation_validator.h" |
| 15 #include "testing/gmock/include/gmock/gmock.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 |
| 18 using installer::ChannelInfo; |
| 19 using installer::InstallationValidator; |
| 20 using installer::InstallationState; |
| 21 using installer::ProductState; |
| 22 using testing::_; |
| 23 using testing::StrictMock; |
| 24 |
| 25 namespace { |
| 26 |
| 27 enum Channel { |
| 28 STABLE_CHANNEL, |
| 29 BETA_CHANNEL, |
| 30 DEV_CHANNEL |
| 31 }; |
| 32 |
| 33 enum PackageType { |
| 34 SINGLE_INSTALL, |
| 35 MULTI_INSTALL |
| 36 }; |
| 37 |
| 38 enum Level { |
| 39 USER_LEVEL, |
| 40 SYSTEM_LEVEL |
| 41 }; |
| 42 |
| 43 enum Vehicle { |
| 44 GOOGLE_UPDATE, |
| 45 MSI |
| 46 }; |
| 47 |
| 48 enum ChannelModifier { |
| 49 CM_MULTI = 0x01, |
| 50 CM_CHROME = 0x02, |
| 51 CM_CHROME_FRAME = 0x04, |
| 52 CM_READY_MODE = 0x08, |
| 53 CM_FULL = 0x10 |
| 54 }; |
| 55 |
| 56 const wchar_t* const kChromeChannels[] = { |
| 57 L"", |
| 58 L"1.1-beta", |
| 59 L"2.0-dev" |
| 60 }; |
| 61 |
| 62 const wchar_t* const kChromeFrameChannels[] = { |
| 63 L"", |
| 64 L"beta", |
| 65 L"dev" |
| 66 }; |
| 67 |
| 68 class FakeProductState : public ProductState { |
| 69 public: |
| 70 void Clear(); |
| 71 void SetChannel(const wchar_t* base, int channel_modifiers); |
| 72 void SetVersion(const char* version); |
| 73 void SetUninstallCommand(BrowserDistribution::Type dist_type, |
| 74 Level install_level, |
| 75 const char* version, |
| 76 int channel_modifiers, |
| 77 Vehicle vehicle); |
| 78 void set_multi_install(bool is_multi_install) { |
| 79 multi_install_ = is_multi_install; |
| 80 } |
| 81 |
| 82 protected: |
| 83 struct ChannelMethodForModifier { |
| 84 ChannelModifier modifier; |
| 85 bool (ChannelInfo::*method)(bool value); |
| 86 }; |
| 87 |
| 88 static const ChannelMethodForModifier kChannelMethods[]; |
| 89 }; |
| 90 |
| 91 class FakeInstallationState : public InstallationState { |
| 92 public: |
| 93 void SetProductState(BrowserDistribution::Type type, |
| 94 Level install_level, |
| 95 const ProductState& product) { |
| 96 GetProducts(install_level)[IndexFromDistType(type)].CopyFrom(product); |
| 97 } |
| 98 |
| 99 protected: |
| 100 ProductState* GetProducts(Level install_level) { |
| 101 return install_level == USER_LEVEL ? user_products_ : system_products_; |
| 102 } |
| 103 }; |
| 104 |
| 105 // static |
| 106 const FakeProductState::ChannelMethodForModifier |
| 107 FakeProductState::kChannelMethods[] = { |
| 108 { CM_MULTI, &ChannelInfo::SetMultiInstall }, |
| 109 { CM_CHROME, &ChannelInfo::SetChrome }, |
| 110 { CM_CHROME_FRAME, &ChannelInfo::SetChromeFrame }, |
| 111 { CM_READY_MODE, &ChannelInfo::SetReadyMode }, |
| 112 { CM_FULL, &ChannelInfo::SetFullSuffix } |
| 113 }; |
| 114 |
| 115 void FakeProductState::Clear() { |
| 116 channel_.set_value(std::wstring()); |
| 117 version_.reset(); |
| 118 old_version_.reset(); |
| 119 rename_cmd_.clear(); |
| 120 uninstall_command_ = CommandLine(CommandLine::NO_PROGRAM); |
| 121 msi_ = false; |
| 122 multi_install_ = false; |
| 123 } |
| 124 |
| 125 // Sets the channel_ member of this instance according to a base channel value |
| 126 // and a set of modifiers. |
| 127 void FakeProductState::SetChannel(const wchar_t* base, int channel_modifiers) { |
| 128 channel_.set_value(base); |
| 129 for (size_t i = 0; i < arraysize(kChannelMethods); ++i) { |
| 130 if ((channel_modifiers & kChannelMethods[i].modifier) != 0) |
| 131 (channel_.*kChannelMethods[i].method)(true); |
| 132 } |
| 133 } |
| 134 |
| 135 void FakeProductState::SetVersion(const char* version) { |
| 136 version_.reset( |
| 137 version == NULL ? NULL : Version::GetVersionFromString(version)); |
| 138 } |
| 139 |
| 140 // Sets the uninstall command for this object. |
| 141 void FakeProductState::SetUninstallCommand(BrowserDistribution::Type dist_type, |
| 142 Level install_level, |
| 143 const char* version, |
| 144 int channel_modifiers, |
| 145 Vehicle vehicle) { |
| 146 DCHECK(version); |
| 147 |
| 148 const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0; |
| 149 FilePath setup_path = installer::GetChromeInstallPath( |
| 150 install_level == SYSTEM_LEVEL, |
| 151 BrowserDistribution::GetSpecificDistribution(is_multi_install ? |
| 152 BrowserDistribution::CHROME_BINARIES : dist_type)); |
| 153 setup_path = setup_path |
| 154 .AppendASCII(version) |
| 155 .Append(installer::kInstallerDir) |
| 156 .Append(installer::kSetupExe); |
| 157 uninstall_command_ = CommandLine(setup_path); |
| 158 uninstall_command_.AppendSwitch(installer::switches::kUninstall); |
| 159 if (install_level == SYSTEM_LEVEL) |
| 160 uninstall_command_.AppendSwitch(installer::switches::kSystemLevel); |
| 161 if (is_multi_install) { |
| 162 uninstall_command_.AppendSwitch(installer::switches::kMultiInstall); |
| 163 if (dist_type == BrowserDistribution::CHROME_BROWSER) { |
| 164 uninstall_command_.AppendSwitch(installer::switches::kChrome); |
| 165 if ((channel_modifiers & CM_READY_MODE) != 0) { |
| 166 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame); |
| 167 uninstall_command_.AppendSwitch( |
| 168 installer::switches::kChromeFrameReadyMode); |
| 169 } |
| 170 } |
| 171 } else if (dist_type == BrowserDistribution::CHROME_FRAME) { |
| 172 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame); |
| 173 } |
| 174 if (vehicle == MSI) |
| 175 uninstall_command_.AppendSwitch(installer::switches::kMsi); |
| 176 } |
| 177 |
| 178 // Populates |chrome_state| with the state of a valid Chrome browser |
| 179 // installation. |channel_modifiers|, a field of bits defined by enum |
| 180 // ChannelModifier, dictate properties of the installation (multi-install, |
| 181 // ready-mode, etc). |
| 182 void MakeChromeState(Level install_level, |
| 183 Channel channel, |
| 184 int channel_modifiers, |
| 185 Vehicle vehicle, |
| 186 FakeProductState* chrome_state) { |
| 187 chrome_state->Clear(); |
| 188 chrome_state->SetChannel(kChromeChannels[channel], channel_modifiers); |
| 189 chrome_state->SetVersion(chrome::kChromeVersion); |
| 190 chrome_state->SetUninstallCommand(BrowserDistribution::CHROME_BROWSER, |
| 191 install_level, chrome::kChromeVersion, |
| 192 channel_modifiers, vehicle); |
| 193 chrome_state->set_multi_install((channel_modifiers & CM_MULTI) != 0); |
| 194 } |
| 195 |
| 196 } // namespace |
| 197 |
| 198 // Fixture for testing the InstallationValidator. Errors logged by the |
| 199 // validator are sent to an optional mock recipient (see |
| 200 // set_validation_error_recipient) upon which expectations can be placed. |
| 201 class InstallationValidatorTest : public testing::Test { |
| 202 protected: |
| 203 class ValidationErrorRecipient { |
| 204 public: |
| 205 virtual ~ValidationErrorRecipient() { } |
| 206 virtual void ReceiveValidationError(const char* file, |
| 207 int line, |
| 208 const char* message) = 0; |
| 209 }; |
| 210 class MockValidationErrorRecipient : public ValidationErrorRecipient { |
| 211 public: |
| 212 MOCK_METHOD3(ReceiveValidationError, void(const char* file, |
| 213 int line, |
| 214 const char* message)); |
| 215 }; |
| 216 |
| 217 static void SetUpTestCase(); |
| 218 static void TearDownTestCase(); |
| 219 static bool HandleLogMessage(int severity, |
| 220 const char* file, |
| 221 int line, |
| 222 size_t message_start, |
| 223 const std::string& str); |
| 224 static void set_validation_error_recipient( |
| 225 ValidationErrorRecipient* recipient); |
| 226 |
| 227 virtual void TearDown(); |
| 228 |
| 229 static logging::LogMessageHandlerFunction old_log_message_handler_; |
| 230 static ValidationErrorRecipient* validation_error_recipient_; |
| 231 }; |
| 232 |
| 233 // static |
| 234 logging::LogMessageHandlerFunction |
| 235 InstallationValidatorTest::old_log_message_handler_ = NULL; |
| 236 |
| 237 // static |
| 238 InstallationValidatorTest::ValidationErrorRecipient* |
| 239 InstallationValidatorTest::validation_error_recipient_ = NULL; |
| 240 |
| 241 // static |
| 242 void InstallationValidatorTest::SetUpTestCase() { |
| 243 old_log_message_handler_ = logging::GetLogMessageHandler(); |
| 244 logging::SetLogMessageHandler(&HandleLogMessage); |
| 245 } |
| 246 |
| 247 // static |
| 248 void InstallationValidatorTest::TearDownTestCase() { |
| 249 logging::SetLogMessageHandler(old_log_message_handler_); |
| 250 old_log_message_handler_ = NULL; |
| 251 } |
| 252 |
| 253 // static |
| 254 bool InstallationValidatorTest::HandleLogMessage(int severity, |
| 255 const char* file, |
| 256 int line, |
| 257 size_t message_start, |
| 258 const std::string& str) { |
| 259 // All validation failures result in LOG(ERROR) |
| 260 if (severity == logging::LOG_ERROR) { |
| 261 if (validation_error_recipient_ != NULL) { |
| 262 validation_error_recipient_->ReceiveValidationError( |
| 263 file, line, str.c_str() + message_start); |
| 264 } else { |
| 265 // Fail the test if an error wasn't handled. |
| 266 ADD_FAILURE_AT(file, line) << (str.c_str() + message_start); |
| 267 } |
| 268 return true; |
| 269 } |
| 270 |
| 271 if (old_log_message_handler_ != NULL) |
| 272 return (old_log_message_handler_)(severity, file, line, message_start, str); |
| 273 |
| 274 return false; |
| 275 } |
| 276 |
| 277 // static |
| 278 void InstallationValidatorTest::set_validation_error_recipient( |
| 279 ValidationErrorRecipient* recipient) { |
| 280 validation_error_recipient_ = recipient; |
| 281 } |
| 282 |
| 283 void InstallationValidatorTest::TearDown() { |
| 284 validation_error_recipient_ = NULL; |
| 285 } |
| 286 |
| 287 // Test that NO_PRODUCTS is returned. |
| 288 TEST_F(InstallationValidatorTest, NoProducts) { |
| 289 InstallationState empty_state; |
| 290 InstallationValidator::InstallationType type = |
| 291 static_cast<InstallationValidator::InstallationType>(-1); |
| 292 StrictMock<MockValidationErrorRecipient> recipient; |
| 293 set_validation_error_recipient(&recipient); |
| 294 |
| 295 EXPECT_TRUE(InstallationValidator::ValidateInstallationTypeForState( |
| 296 empty_state, true, &type)); |
| 297 EXPECT_EQ(InstallationValidator::NO_PRODUCTS, type); |
| 298 } |
| 299 |
| 300 // Test valid single Chrome. |
| 301 TEST_F(InstallationValidatorTest, ChromeVersion) { |
| 302 FakeProductState chrome_state; |
| 303 FakeInstallationState machine_state; |
| 304 InstallationValidator::InstallationType type; |
| 305 StrictMock<MockValidationErrorRecipient> recipient; |
| 306 set_validation_error_recipient(&recipient); |
| 307 |
| 308 MakeChromeState(SYSTEM_LEVEL, STABLE_CHANNEL, 0, GOOGLE_UPDATE, |
| 309 &chrome_state); |
| 310 machine_state.SetProductState(BrowserDistribution::CHROME_BROWSER, |
| 311 SYSTEM_LEVEL, chrome_state); |
| 312 EXPECT_TRUE(InstallationValidator::ValidateInstallationTypeForState( |
| 313 machine_state, true, &type)); |
| 314 EXPECT_EQ(InstallationValidator::CHROME_SINGLE, type); |
| 315 } |
| OLD | NEW |