Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / installer / util / installation_validator_unittest.cc
blobd5abb1392023f1622c62f8dc7a62bd04a8da6290
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 AddInstallExtensionCommand(BrowserDistribution::Type dist_type,
82 Level install_level,
83 const char* version,
84 int channel_modifiers);
85 void AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
86 Level install_level,
87 const char* version,
88 int channel_modifiers);
89 void AddQueryEULAAcceptanceCommand(BrowserDistribution::Type dist_type,
90 Level install_level,
91 const char* version,
92 int channel_modifiers);
93 void AddQuickEnableApplicationHostCommand(BrowserDistribution::Type dist_type,
94 Level install_level,
95 const char* version,
96 int channel_modifiers);
97 void set_multi_install(bool is_multi_install) {
98 multi_install_ = is_multi_install;
100 installer::AppCommands& commands() { return commands_; }
102 protected:
103 struct ChannelMethodForModifier {
104 ChannelModifier modifier;
105 bool (ChannelInfo::*method)(bool value);
108 static base::FilePath GetSetupPath(
109 BrowserDistribution::Type dist_type,
110 Level install_level,
111 int channel_modifiers);
113 static base::FilePath GetSetupExePath(
114 BrowserDistribution::Type dist_type,
115 Level install_level,
116 const char* version,
117 int channel_modifiers);
119 static const ChannelMethodForModifier kChannelMethods[];
122 class FakeInstallationState : public InstallationState {
123 public:
124 void SetProductState(BrowserDistribution::Type type,
125 Level install_level,
126 const ProductState& product) {
127 GetProducts(install_level)[IndexFromDistType(type)].CopyFrom(product);
130 protected:
131 ProductState* GetProducts(Level install_level) {
132 return install_level == USER_LEVEL ? user_products_ : system_products_;
136 // static
137 const FakeProductState::ChannelMethodForModifier
138 FakeProductState::kChannelMethods[] = {
139 { CM_MULTI, &ChannelInfo::SetMultiInstall },
140 { CM_CHROME, &ChannelInfo::SetChrome },
141 { CM_CHROME_FRAME, &ChannelInfo::SetChromeFrame },
142 { CM_FULL, &ChannelInfo::SetFullSuffix }
145 // static
146 base::FilePath FakeProductState::GetSetupPath(
147 BrowserDistribution::Type dist_type,
148 Level install_level,
149 int channel_modifiers) {
150 const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
151 return installer::GetChromeInstallPath(
152 install_level == SYSTEM_LEVEL,
153 BrowserDistribution::GetSpecificDistribution(is_multi_install ?
154 BrowserDistribution::CHROME_BINARIES : dist_type));
157 // static
158 base::FilePath FakeProductState::GetSetupExePath(
159 BrowserDistribution::Type dist_type,
160 Level install_level,
161 const char* version,
162 int channel_modifiers) {
163 base::FilePath setup_path = GetSetupPath(dist_type, install_level,
164 channel_modifiers);
165 return setup_path
166 .AppendASCII(version)
167 .Append(installer::kInstallerDir)
168 .Append(installer::kSetupExe);
171 // Sets the channel_ member of this instance according to a base channel value
172 // and a set of modifiers.
173 void FakeProductState::SetChannel(const wchar_t* base, int channel_modifiers) {
174 channel_.set_value(base);
175 for (size_t i = 0; i < arraysize(kChannelMethods); ++i) {
176 if ((channel_modifiers & kChannelMethods[i].modifier) != 0)
177 (channel_.*kChannelMethods[i].method)(true);
181 void FakeProductState::SetVersion(const char* version) {
182 version_.reset(version == NULL ? NULL : new Version(version));
185 // Sets the uninstall command for this object.
186 void FakeProductState::SetUninstallCommand(BrowserDistribution::Type dist_type,
187 Level install_level,
188 const char* version,
189 int channel_modifiers,
190 Vehicle vehicle) {
191 DCHECK(version);
193 const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
194 uninstall_command_ = CommandLine(GetSetupExePath(dist_type, install_level,
195 version, channel_modifiers));
196 uninstall_command_.AppendSwitch(installer::switches::kUninstall);
197 if (install_level == SYSTEM_LEVEL)
198 uninstall_command_.AppendSwitch(installer::switches::kSystemLevel);
199 if (is_multi_install) {
200 uninstall_command_.AppendSwitch(installer::switches::kMultiInstall);
201 if (dist_type == BrowserDistribution::CHROME_BROWSER)
202 uninstall_command_.AppendSwitch(installer::switches::kChrome);
203 else if (dist_type == BrowserDistribution::CHROME_FRAME)
204 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
205 } else if (dist_type == BrowserDistribution::CHROME_FRAME) {
206 uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
208 if (vehicle == MSI)
209 uninstall_command_.AppendSwitch(installer::switches::kMsi);
212 // Adds the "install-extension" Google Update product command.
213 void FakeProductState::AddInstallExtensionCommand(
214 BrowserDistribution::Type dist_type,
215 Level install_level,
216 const char* version,
217 int channel_modifiers) {
218 // Right now only Chrome browser uses this.
219 DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BROWSER);
221 CommandLine cmd_line(GetSetupPath(dist_type, install_level,
222 channel_modifiers).
223 Append(installer::kChromeExe));
224 cmd_line.AppendSwitchASCII(::switches::kLimitedInstallFromWebstore, "%1");
225 AppCommand app_cmd(cmd_line.GetCommandLineString());
226 app_cmd.set_sends_pings(true);
227 app_cmd.set_is_web_accessible(true);
228 app_cmd.set_is_run_as_user(true);
229 commands_.Set(installer::kCmdInstallExtension, app_cmd);
232 // Adds the "on-os-upgrade" Google Update product command.
233 void FakeProductState::AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
234 Level install_level,
235 const char* version,
236 int channel_modifiers) {
237 // Right now only Chrome browser uses this.
238 DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BROWSER);
240 CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
241 channel_modifiers));
242 cmd_line.AppendSwitch(installer::switches::kOnOsUpgrade);
243 // Imitating ChromeBrowserOperations::AppendProductFlags().
244 if ((channel_modifiers & CM_MULTI) != 0) {
245 cmd_line.AppendSwitch(installer::switches::kMultiInstall);
246 cmd_line.AppendSwitch(installer::switches::kChrome);
248 if (install_level == SYSTEM_LEVEL)
249 cmd_line.AppendSwitch(installer::switches::kSystemLevel);
250 cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
251 AppCommand app_cmd(cmd_line.GetCommandLineString());
252 app_cmd.set_is_auto_run_on_os_upgrade(true);
253 commands_.Set(installer::kCmdOnOsUpgrade, app_cmd);
256 // Adds the "query-eula-acceptance" Google Update product command.
257 void FakeProductState::AddQueryEULAAcceptanceCommand(
258 BrowserDistribution::Type dist_type,
259 Level install_level,
260 const char* version,
261 int channel_modifiers) {
262 DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES);
264 CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
265 channel_modifiers));
266 cmd_line.AppendSwitch(installer::switches::kQueryEULAAcceptance);
267 if (install_level == SYSTEM_LEVEL)
268 cmd_line.AppendSwitch(installer::switches::kSystemLevel);
269 cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
270 AppCommand app_cmd(cmd_line.GetCommandLineString());
271 app_cmd.set_is_web_accessible(true);
272 app_cmd.set_is_run_as_user(true);
273 commands_.Set(installer::kCmdQueryEULAAcceptance, app_cmd);
276 // Adds the "quick-enable-application-host" Google Update product command.
277 void FakeProductState::AddQuickEnableApplicationHostCommand(
278 BrowserDistribution::Type dist_type,
279 Level install_level,
280 const char* version,
281 int channel_modifiers) {
282 DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES);
283 DCHECK_NE(channel_modifiers & CM_MULTI, 0);
285 CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
286 channel_modifiers));
287 cmd_line.AppendSwitch(installer::switches::kMultiInstall);
288 cmd_line.AppendSwitch(installer::switches::kChromeAppLauncher);
289 cmd_line.AppendSwitch(installer::switches::kEnsureGoogleUpdatePresent);
290 AppCommand app_cmd(cmd_line.GetCommandLineString());
291 app_cmd.set_sends_pings(true);
292 app_cmd.set_is_web_accessible(true);
293 app_cmd.set_is_run_as_user(true);
294 commands_.Set(installer::kCmdQuickEnableApplicationHost, app_cmd);
297 } // namespace
299 // Fixture for testing the InstallationValidator. Errors logged by the
300 // validator are sent to an optional mock recipient (see
301 // set_validation_error_recipient) upon which expectations can be placed.
302 class InstallationValidatorTest
303 : public testing::TestWithParam<InstallationValidator::InstallationType> {
304 public:
306 // These shouldn't need to be public, but there seems to be some interaction
307 // with parameterized tests that requires it.
308 static void SetUpTestCase();
309 static void TearDownTestCase();
311 // Returns the multi channel modifiers for a given installation type.
312 static int GetChannelModifiers(InstallationValidator::InstallationType type);
314 protected:
315 typedef std::map<InstallationValidator::InstallationType, int>
316 InstallationTypeToModifiers;
318 class ValidationErrorRecipient {
319 public:
320 virtual ~ValidationErrorRecipient() { }
321 virtual void ReceiveValidationError(const char* file,
322 int line,
323 const char* message) = 0;
325 class MockValidationErrorRecipient : public ValidationErrorRecipient {
326 public:
327 MOCK_METHOD3(ReceiveValidationError, void(const char* file,
328 int line,
329 const char* message));
332 protected:
333 static bool HandleLogMessage(int severity,
334 const char* file,
335 int line,
336 size_t message_start,
337 const std::string& str);
338 static void set_validation_error_recipient(
339 ValidationErrorRecipient* recipient);
340 static void MakeProductState(
341 BrowserDistribution::Type prod_type,
342 InstallationValidator::InstallationType inst_type,
343 Level install_level,
344 Channel channel,
345 Vehicle vehicle,
346 FakeProductState* state);
347 static void MakeMachineState(
348 InstallationValidator::InstallationType inst_type,
349 Level install_level,
350 Channel channel,
351 Vehicle vehicle,
352 FakeInstallationState* state);
353 virtual void TearDown();
355 static logging::LogMessageHandlerFunction old_log_message_handler_;
356 static ValidationErrorRecipient* validation_error_recipient_;
357 static InstallationTypeToModifiers* type_to_modifiers_;
360 // static
361 logging::LogMessageHandlerFunction
362 InstallationValidatorTest::old_log_message_handler_ = NULL;
364 // static
365 InstallationValidatorTest::ValidationErrorRecipient*
366 InstallationValidatorTest::validation_error_recipient_ = NULL;
368 // static
369 InstallationValidatorTest::InstallationTypeToModifiers*
370 InstallationValidatorTest::type_to_modifiers_ = NULL;
372 // static
373 int InstallationValidatorTest::GetChannelModifiers(
374 InstallationValidator::InstallationType type) {
375 DCHECK(type_to_modifiers_);
376 DCHECK(type_to_modifiers_->find(type) != type_to_modifiers_->end());
378 return (*type_to_modifiers_)[type];
381 // static
382 void InstallationValidatorTest::SetUpTestCase() {
383 DCHECK(type_to_modifiers_ == NULL);
384 old_log_message_handler_ = logging::GetLogMessageHandler();
385 logging::SetLogMessageHandler(&HandleLogMessage);
387 type_to_modifiers_ = new InstallationTypeToModifiers();
388 InstallationTypeToModifiers& ttm = *type_to_modifiers_;
389 ttm[InstallationValidator::NO_PRODUCTS] = 0;
390 ttm[InstallationValidator::CHROME_SINGLE] = 0;
391 ttm[InstallationValidator::CHROME_MULTI] = CM_MULTI | CM_CHROME;
392 ttm[InstallationValidator::CHROME_FRAME_SINGLE] = 0;
393 ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE] = 0;
394 ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI] =
395 CM_MULTI | CM_CHROME;
396 ttm[InstallationValidator::CHROME_FRAME_MULTI] = CM_MULTI | CM_CHROME_FRAME;
397 ttm[InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI] =
398 CM_MULTI | CM_CHROME_FRAME | CM_CHROME;
401 // static
402 void InstallationValidatorTest::TearDownTestCase() {
403 logging::SetLogMessageHandler(old_log_message_handler_);
404 old_log_message_handler_ = NULL;
406 delete type_to_modifiers_;
407 type_to_modifiers_ = NULL;
410 // static
411 bool InstallationValidatorTest::HandleLogMessage(int severity,
412 const char* file,
413 int line,
414 size_t message_start,
415 const std::string& str) {
416 // All validation failures result in LOG(ERROR)
417 if (severity == logging::LOG_ERROR && !str.empty()) {
418 // Remove the trailing newline, if present.
419 size_t message_length = str.size() - message_start;
420 if (*str.rbegin() == '\n')
421 --message_length;
422 if (validation_error_recipient_ != NULL) {
423 validation_error_recipient_->ReceiveValidationError(
424 file, line, str.substr(message_start, message_length).c_str());
425 } else {
426 // Fail the test if an error wasn't handled.
427 ADD_FAILURE_AT(file, line)
428 << base::StringPiece(str.c_str() + message_start, message_length);
430 return true;
433 if (old_log_message_handler_ != NULL)
434 return (old_log_message_handler_)(severity, file, line, message_start, str);
436 return false;
439 // static
440 void InstallationValidatorTest::set_validation_error_recipient(
441 ValidationErrorRecipient* recipient) {
442 validation_error_recipient_ = recipient;
445 // static
446 // Populates |state| with the state of a valid installation of product
447 // |prod_type|. |inst_type| dictates properties of the installation
448 // (multi-install, etc).
449 void InstallationValidatorTest::MakeProductState(
450 BrowserDistribution::Type prod_type,
451 InstallationValidator::InstallationType inst_type,
452 Level install_level,
453 Channel channel,
454 Vehicle vehicle,
455 FakeProductState* state) {
456 DCHECK(state);
458 const bool is_multi_install =
459 prod_type == BrowserDistribution::CHROME_BINARIES ||
460 (prod_type == BrowserDistribution::CHROME_BROWSER &&
461 (inst_type & InstallationValidator::ProductBits::CHROME_MULTI) != 0) ||
462 (prod_type == BrowserDistribution::CHROME_FRAME &&
463 (inst_type &
464 InstallationValidator::ProductBits::CHROME_FRAME_MULTI) != 0);
466 const wchar_t* const* channels = &kChromeChannels[0];
467 if (prod_type == BrowserDistribution::CHROME_FRAME && !is_multi_install)
468 channels = &kChromeFrameChannels[0]; // SxS GCF has its own channel names.
469 const int channel_modifiers =
470 is_multi_install ? GetChannelModifiers(inst_type) : 0;
472 state->Clear();
473 state->SetChannel(channels[channel], channel_modifiers);
474 state->SetVersion(chrome::kChromeVersion);
475 state->SetUninstallCommand(prod_type, install_level, chrome::kChromeVersion,
476 channel_modifiers, vehicle);
477 state->set_multi_install(is_multi_install);
478 if (prod_type == BrowserDistribution::CHROME_BINARIES) {
479 state->AddQueryEULAAcceptanceCommand(prod_type,
480 install_level,
481 chrome::kChromeVersion,
482 channel_modifiers);
484 if (prod_type == BrowserDistribution::CHROME_BINARIES) {
485 state->AddQuickEnableApplicationHostCommand(prod_type,
486 install_level,
487 chrome::kChromeVersion,
488 channel_modifiers);
490 if (prod_type == BrowserDistribution::CHROME_BROWSER) {
491 state->AddOsUpgradeCommand(prod_type,
492 install_level,
493 chrome::kChromeVersion,
494 channel_modifiers);
495 state->AddInstallExtensionCommand(prod_type,
496 install_level,
497 chrome::kChromeVersion,
498 channel_modifiers);
502 // static
503 // Populates |state| with the state of a valid installation of |inst_type|.
504 void InstallationValidatorTest::MakeMachineState(
505 InstallationValidator::InstallationType inst_type,
506 Level install_level,
507 Channel channel,
508 Vehicle vehicle,
509 FakeInstallationState* state) {
510 DCHECK(state);
512 static const int kChromeMask =
513 (InstallationValidator::ProductBits::CHROME_SINGLE |
514 InstallationValidator::ProductBits::CHROME_MULTI);
515 static const int kChromeFrameMask =
516 (InstallationValidator::ProductBits::CHROME_FRAME_SINGLE |
517 InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
518 static const int kBinariesMask =
519 (InstallationValidator::ProductBits::CHROME_MULTI |
520 InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
522 FakeProductState prod_state;
524 if ((inst_type & kChromeMask) != 0) {
525 MakeProductState(BrowserDistribution::CHROME_BROWSER, inst_type,
526 install_level, channel, vehicle, &prod_state);
527 state->SetProductState(BrowserDistribution::CHROME_BROWSER, install_level,
528 prod_state);
531 if ((inst_type & kChromeFrameMask) != 0) {
532 MakeProductState(BrowserDistribution::CHROME_FRAME, inst_type,
533 install_level, channel, vehicle, &prod_state);
534 state->SetProductState(BrowserDistribution::CHROME_FRAME, install_level,
535 prod_state);
538 if ((inst_type & kBinariesMask) != 0) {
539 MakeProductState(BrowserDistribution::CHROME_BINARIES, inst_type,
540 install_level, channel, vehicle, &prod_state);
541 state->SetProductState(BrowserDistribution::CHROME_BINARIES, install_level,
542 prod_state);
546 void InstallationValidatorTest::TearDown() {
547 validation_error_recipient_ = NULL;
550 // Builds a proper machine state for a given InstallationType, then validates
551 // it.
552 TEST_P(InstallationValidatorTest, TestValidInstallation) {
553 const InstallationValidator::InstallationType inst_type = GetParam();
554 FakeInstallationState machine_state;
555 InstallationValidator::InstallationType type;
556 StrictMock<MockValidationErrorRecipient> recipient;
557 set_validation_error_recipient(&recipient);
559 MakeMachineState(inst_type, SYSTEM_LEVEL, STABLE_CHANNEL, GOOGLE_UPDATE,
560 &machine_state);
561 EXPECT_TRUE(InstallationValidator::ValidateInstallationTypeForState(
562 machine_state, true, &type));
563 EXPECT_EQ(inst_type, type);
566 // Run the test for all installation types.
567 INSTANTIATE_TEST_CASE_P(
568 AllValidInstallations,
569 InstallationValidatorTest,
570 Values(InstallationValidator::NO_PRODUCTS,
571 InstallationValidator::CHROME_SINGLE,
572 InstallationValidator::CHROME_MULTI,
573 InstallationValidator::CHROME_FRAME_SINGLE,
574 InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE,
575 InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI,
576 InstallationValidator::CHROME_FRAME_MULTI,
577 InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI));