Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / installer / util / installation_validator_unittest.cc
blob65b9756aec4933f96472e83a8b04640e3b9d7ec7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <map>
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/version.h"
12 #include "chrome/common/chrome_constants.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/installer/util/channel_info.h"
15 #include "chrome/installer/util/helper.h"
16 #include "chrome/installer/util/installation_state.h"
17 #include "chrome/installer/util/installation_validator.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using installer::ChannelInfo;
22 using installer::InstallationValidator;
23 using installer::InstallationState;
24 using installer::AppCommand;
25 using installer::ProductState;
26 using testing::_;
27 using testing::StrictMock;
28 using testing::Values;
30 namespace {
32 enum Channel {
33 STABLE_CHANNEL,
34 BETA_CHANNEL,
35 DEV_CHANNEL
38 enum PackageType {
39 SINGLE_INSTALL,
40 MULTI_INSTALL
43 enum Level {
44 USER_LEVEL,
45 SYSTEM_LEVEL
48 enum Vehicle {
49 GOOGLE_UPDATE,
50 MSI
53 enum ChannelModifier {
54 CM_MULTI = 0x01,
55 CM_CHROME = 0x02,
56 CM_CHROME_FRAME = 0x04,
57 CM_FULL = 0x08
60 const wchar_t* const kChromeChannels[] = {
61 L"",
62 L"1.1-beta",
63 L"2.0-dev"
66 const wchar_t* const kChromeFrameChannels[] = {
67 L"",
68 L"beta",
69 L"dev"
72 class FakeProductState : public ProductState {
73 public:
74 void SetChannel(const wchar_t* base, int channel_modifiers);
75 void SetVersion(const char* version);
76 void SetUninstallCommand(BrowserDistribution::Type dist_type,
77 Level install_level,
78 const char* version,
79 int channel_modifiers,
80 Vehicle vehicle);
81 void AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
82 Level install_level,
83 const char* version,
84 int channel_modifiers);
85 void set_multi_install(bool is_multi_install) {
86 multi_install_ = is_multi_install;
88 installer::AppCommands& commands() { return commands_; }
90 protected:
91 struct ChannelMethodForModifier {
92 ChannelModifier modifier;
93 bool (ChannelInfo::*method)(bool value);
96 static base::FilePath GetSetupPath(
97 BrowserDistribution::Type dist_type,
98 Level install_level,
99 int channel_modifiers);
101 static base::FilePath GetSetupExePath(
102 BrowserDistribution::Type dist_type,
103 Level install_level,
104 const char* version,
105 int channel_modifiers);
107 static const ChannelMethodForModifier kChannelMethods[];
110 class FakeInstallationState : public InstallationState {
111 public:
112 void SetProductState(BrowserDistribution::Type type,
113 Level install_level,
114 const ProductState& product) {
115 GetProducts(install_level)[IndexFromDistType(type)].CopyFrom(product);
118 protected:
119 ProductState* GetProducts(Level install_level) {
120 return install_level == USER_LEVEL ? user_products_ : system_products_;
124 // static
125 const FakeProductState::ChannelMethodForModifier
126 FakeProductState::kChannelMethods[] = {
127 { CM_MULTI, &ChannelInfo::SetMultiInstall },
128 { CM_CHROME, &ChannelInfo::SetChrome },
129 { CM_CHROME_FRAME, &ChannelInfo::SetChromeFrame },
130 { CM_FULL, &ChannelInfo::SetFullSuffix }
133 // static
134 base::FilePath FakeProductState::GetSetupPath(
135 BrowserDistribution::Type dist_type,
136 Level install_level,
137 int channel_modifiers) {
138 const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
139 return installer::GetChromeInstallPath(
140 install_level == SYSTEM_LEVEL,
141 BrowserDistribution::GetSpecificDistribution(is_multi_install ?
142 BrowserDistribution::CHROME_BINARIES : dist_type));
145 // static
146 base::FilePath FakeProductState::GetSetupExePath(
147 BrowserDistribution::Type dist_type,
148 Level install_level,
149 const char* version,
150 int channel_modifiers) {
151 base::FilePath setup_path = GetSetupPath(dist_type, install_level,
152 channel_modifiers);
153 return setup_path
154 .AppendASCII(version)
155 .Append(installer::kInstallerDir)
156 .Append(installer::kSetupExe);
159 // Sets the channel_ member of this instance according to a base channel value
160 // and a set of modifiers.
161 void FakeProductState::SetChannel(const wchar_t* base, int channel_modifiers) {
162 channel_.set_value(base);
163 for (size_t i = 0; i < arraysize(kChannelMethods); ++i) {
164 if ((channel_modifiers & kChannelMethods[i].modifier) != 0)
165 (channel_.*kChannelMethods[i].method)(true);
169 void FakeProductState::SetVersion(const char* version) {
170 version_.reset(version == NULL ? NULL : new Version(version));
173 // Sets the uninstall command for this object.
174 void FakeProductState::SetUninstallCommand(BrowserDistribution::Type dist_type,
175 Level install_level,
176 const char* version,
177 int channel_modifiers,
178 Vehicle vehicle) {
179 DCHECK(version);
181 const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
182 uninstall_command_ = base::CommandLine(
183 GetSetupExePath(dist_type, install_level, version, channel_modifiers));
184 uninstall_command_.AppendSwitch(installer::switches::kUninstall);
185 if (install_level == SYSTEM_LEVEL)
186 uninstall_command_.AppendSwitch(installer::switches::kSystemLevel);
187 if (is_multi_install) {
188 uninstall_command_.AppendSwitch(installer::switches::kMultiInstall);
189 if (dist_type == BrowserDistribution::CHROME_BROWSER)
190 uninstall_command_.AppendSwitch(installer::switches::kChrome);
191 else if (dist_type == BrowserDistribution::CHROME_FRAME)
192 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
193 } else if (dist_type == BrowserDistribution::CHROME_FRAME) {
194 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
196 if (vehicle == MSI)
197 uninstall_command_.AppendSwitch(installer::switches::kMsi);
200 // Adds the "on-os-upgrade" Google Update product command.
201 void FakeProductState::AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
202 Level install_level,
203 const char* version,
204 int channel_modifiers) {
205 // Right now only Chrome browser uses this.
206 DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BROWSER);
208 base::CommandLine cmd_line(
209 GetSetupExePath(dist_type, install_level, version, channel_modifiers));
210 cmd_line.AppendSwitch(installer::switches::kOnOsUpgrade);
211 // Imitating ChromeBrowserOperations::AppendProductFlags().
212 if ((channel_modifiers & CM_MULTI) != 0) {
213 cmd_line.AppendSwitch(installer::switches::kMultiInstall);
214 cmd_line.AppendSwitch(installer::switches::kChrome);
216 if (install_level == SYSTEM_LEVEL)
217 cmd_line.AppendSwitch(installer::switches::kSystemLevel);
218 cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
219 AppCommand app_cmd(cmd_line.GetCommandLineString());
220 app_cmd.set_is_auto_run_on_os_upgrade(true);
221 commands_.Set(installer::kCmdOnOsUpgrade, app_cmd);
224 } // namespace
226 // Fixture for testing the InstallationValidator. Errors logged by the
227 // validator are sent to an optional mock recipient (see
228 // set_validation_error_recipient) upon which expectations can be placed.
229 class InstallationValidatorTest
230 : public testing::TestWithParam<InstallationValidator::InstallationType> {
231 public:
233 // These shouldn't need to be public, but there seems to be some interaction
234 // with parameterized tests that requires it.
235 static void SetUpTestCase();
236 static void TearDownTestCase();
238 // Returns the multi channel modifiers for a given installation type.
239 static int GetChannelModifiers(InstallationValidator::InstallationType type);
241 protected:
242 typedef std::map<InstallationValidator::InstallationType, int>
243 InstallationTypeToModifiers;
245 class ValidationErrorRecipient {
246 public:
247 virtual ~ValidationErrorRecipient() { }
248 virtual void ReceiveValidationError(const char* file,
249 int line,
250 const char* message) = 0;
252 class MockValidationErrorRecipient : public ValidationErrorRecipient {
253 public:
254 MOCK_METHOD3(ReceiveValidationError, void(const char* file,
255 int line,
256 const char* message));
259 protected:
260 static bool HandleLogMessage(int severity,
261 const char* file,
262 int line,
263 size_t message_start,
264 const std::string& str);
265 static void set_validation_error_recipient(
266 ValidationErrorRecipient* recipient);
267 static void MakeProductState(
268 BrowserDistribution::Type prod_type,
269 InstallationValidator::InstallationType inst_type,
270 Level install_level,
271 Channel channel,
272 Vehicle vehicle,
273 FakeProductState* state);
274 static void MakeMachineState(
275 InstallationValidator::InstallationType inst_type,
276 Level install_level,
277 Channel channel,
278 Vehicle vehicle,
279 FakeInstallationState* state);
280 void TearDown() override;
282 static logging::LogMessageHandlerFunction old_log_message_handler_;
283 static ValidationErrorRecipient* validation_error_recipient_;
284 static InstallationTypeToModifiers* type_to_modifiers_;
287 // static
288 logging::LogMessageHandlerFunction
289 InstallationValidatorTest::old_log_message_handler_ = NULL;
291 // static
292 InstallationValidatorTest::ValidationErrorRecipient*
293 InstallationValidatorTest::validation_error_recipient_ = NULL;
295 // static
296 InstallationValidatorTest::InstallationTypeToModifiers*
297 InstallationValidatorTest::type_to_modifiers_ = NULL;
299 // static
300 int InstallationValidatorTest::GetChannelModifiers(
301 InstallationValidator::InstallationType type) {
302 DCHECK(type_to_modifiers_);
303 DCHECK(type_to_modifiers_->find(type) != type_to_modifiers_->end());
305 return (*type_to_modifiers_)[type];
308 // static
309 void InstallationValidatorTest::SetUpTestCase() {
310 DCHECK(type_to_modifiers_ == NULL);
311 old_log_message_handler_ = logging::GetLogMessageHandler();
312 logging::SetLogMessageHandler(&HandleLogMessage);
314 type_to_modifiers_ = new InstallationTypeToModifiers();
315 InstallationTypeToModifiers& ttm = *type_to_modifiers_;
316 ttm[InstallationValidator::NO_PRODUCTS] = 0;
317 ttm[InstallationValidator::CHROME_SINGLE] = 0;
318 ttm[InstallationValidator::CHROME_MULTI] = CM_MULTI | CM_CHROME;
319 ttm[InstallationValidator::CHROME_FRAME_SINGLE] = 0;
320 ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE] = 0;
321 ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI] =
322 CM_MULTI | CM_CHROME;
323 ttm[InstallationValidator::CHROME_FRAME_MULTI] = CM_MULTI | CM_CHROME_FRAME;
324 ttm[InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI] =
325 CM_MULTI | CM_CHROME_FRAME | CM_CHROME;
328 // static
329 void InstallationValidatorTest::TearDownTestCase() {
330 logging::SetLogMessageHandler(old_log_message_handler_);
331 old_log_message_handler_ = NULL;
333 delete type_to_modifiers_;
334 type_to_modifiers_ = NULL;
337 // static
338 bool InstallationValidatorTest::HandleLogMessage(int severity,
339 const char* file,
340 int line,
341 size_t message_start,
342 const std::string& str) {
343 // All validation failures result in LOG(ERROR)
344 if (severity == logging::LOG_ERROR && !str.empty()) {
345 // Remove the trailing newline, if present.
346 size_t message_length = str.size() - message_start;
347 if (*str.rbegin() == '\n')
348 --message_length;
349 if (validation_error_recipient_ != NULL) {
350 validation_error_recipient_->ReceiveValidationError(
351 file, line, str.substr(message_start, message_length).c_str());
352 } else {
353 // Fail the test if an error wasn't handled.
354 ADD_FAILURE_AT(file, line)
355 << base::StringPiece(str.c_str() + message_start, message_length);
357 return true;
360 if (old_log_message_handler_ != NULL)
361 return (old_log_message_handler_)(severity, file, line, message_start, str);
363 return false;
366 // static
367 void InstallationValidatorTest::set_validation_error_recipient(
368 ValidationErrorRecipient* recipient) {
369 validation_error_recipient_ = recipient;
372 // static
373 // Populates |state| with the state of a valid installation of product
374 // |prod_type|. |inst_type| dictates properties of the installation
375 // (multi-install, etc).
376 void InstallationValidatorTest::MakeProductState(
377 BrowserDistribution::Type prod_type,
378 InstallationValidator::InstallationType inst_type,
379 Level install_level,
380 Channel channel,
381 Vehicle vehicle,
382 FakeProductState* state) {
383 DCHECK(state);
385 const bool is_multi_install =
386 prod_type == BrowserDistribution::CHROME_BINARIES ||
387 (prod_type == BrowserDistribution::CHROME_BROWSER &&
388 (inst_type & InstallationValidator::ProductBits::CHROME_MULTI) != 0) ||
389 (prod_type == BrowserDistribution::CHROME_FRAME &&
390 (inst_type &
391 InstallationValidator::ProductBits::CHROME_FRAME_MULTI) != 0);
393 const wchar_t* const* channels = &kChromeChannels[0];
394 if (prod_type == BrowserDistribution::CHROME_FRAME && !is_multi_install)
395 channels = &kChromeFrameChannels[0]; // SxS GCF has its own channel names.
396 const int channel_modifiers =
397 is_multi_install ? GetChannelModifiers(inst_type) : 0;
399 state->Clear();
400 state->SetChannel(channels[channel], channel_modifiers);
401 state->SetVersion(chrome::kChromeVersion);
402 state->SetUninstallCommand(prod_type, install_level, chrome::kChromeVersion,
403 channel_modifiers, vehicle);
404 state->set_multi_install(is_multi_install);
405 if (prod_type == BrowserDistribution::CHROME_BROWSER) {
406 state->AddOsUpgradeCommand(prod_type,
407 install_level,
408 chrome::kChromeVersion,
409 channel_modifiers);
413 // static
414 // Populates |state| with the state of a valid installation of |inst_type|.
415 void InstallationValidatorTest::MakeMachineState(
416 InstallationValidator::InstallationType inst_type,
417 Level install_level,
418 Channel channel,
419 Vehicle vehicle,
420 FakeInstallationState* state) {
421 DCHECK(state);
423 static const int kChromeMask =
424 (InstallationValidator::ProductBits::CHROME_SINGLE |
425 InstallationValidator::ProductBits::CHROME_MULTI);
426 static const int kChromeFrameMask =
427 (InstallationValidator::ProductBits::CHROME_FRAME_SINGLE |
428 InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
429 static const int kBinariesMask =
430 (InstallationValidator::ProductBits::CHROME_MULTI |
431 InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
433 FakeProductState prod_state;
435 if ((inst_type & kChromeMask) != 0) {
436 MakeProductState(BrowserDistribution::CHROME_BROWSER, inst_type,
437 install_level, channel, vehicle, &prod_state);
438 state->SetProductState(BrowserDistribution::CHROME_BROWSER, install_level,
439 prod_state);
442 if ((inst_type & kChromeFrameMask) != 0) {
443 MakeProductState(BrowserDistribution::CHROME_FRAME, inst_type,
444 install_level, channel, vehicle, &prod_state);
445 state->SetProductState(BrowserDistribution::CHROME_FRAME, install_level,
446 prod_state);
449 if ((inst_type & kBinariesMask) != 0) {
450 MakeProductState(BrowserDistribution::CHROME_BINARIES, inst_type,
451 install_level, channel, vehicle, &prod_state);
452 state->SetProductState(BrowserDistribution::CHROME_BINARIES, install_level,
453 prod_state);
457 void InstallationValidatorTest::TearDown() {
458 validation_error_recipient_ = NULL;
461 // Builds a proper machine state for a given InstallationType, then validates
462 // it.
463 TEST_P(InstallationValidatorTest, TestValidInstallation) {
464 const InstallationValidator::InstallationType inst_type = GetParam();
465 FakeInstallationState machine_state;
466 InstallationValidator::InstallationType type;
467 StrictMock<MockValidationErrorRecipient> recipient;
468 set_validation_error_recipient(&recipient);
470 MakeMachineState(inst_type, SYSTEM_LEVEL, STABLE_CHANNEL, GOOGLE_UPDATE,
471 &machine_state);
472 EXPECT_TRUE(InstallationValidator::ValidateInstallationTypeForState(
473 machine_state, true, &type));
474 EXPECT_EQ(inst_type, type);
477 // Run the test for all installation types.
478 INSTANTIATE_TEST_CASE_P(
479 AllValidInstallations,
480 InstallationValidatorTest,
481 Values(InstallationValidator::NO_PRODUCTS,
482 InstallationValidator::CHROME_SINGLE,
483 InstallationValidator::CHROME_MULTI,
484 InstallationValidator::CHROME_FRAME_SINGLE,
485 InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE,
486 InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI,
487 InstallationValidator::CHROME_FRAME_MULTI,
488 InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI));