Commit f9178f09 authored by Maciek Kumorek's avatar Maciek Kumorek Committed by Commit Bot

Add a switch to simulate errors in the about page

Add --simulate-update-hresult and --simulate-update-error-code
switches. The first switch can take the HRESULT error code value,
the second one specifies a value that corresponds to the
GoolgeUpdateErrorCode enum. With these switches, when using
VersionUpdaterWin, one can simulate errors in the about page to debug
how the UI reflects certain errors conditions.

Bug: 1066529
Change-Id: I6500b81108c69d252087ebcdb1cba0ffba86dbed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2131019
Commit-Queue: Maciek Kumorek <makumo@microsoft.com>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Reviewed-by: default avatarSorin Jianu <sorin@chromium.org>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#760218}
parent a68c16b3
...@@ -4082,6 +4082,8 @@ jumbo_static_library("browser") { ...@@ -4082,6 +4082,8 @@ jumbo_static_library("browser") {
"google/google_update_policy_fetcher_win.h", "google/google_update_policy_fetcher_win.h",
"google/google_update_win.cc", "google/google_update_win.cc",
"google/google_update_win.h", "google/google_update_win.h",
"google/switches.cc",
"google/switches.h",
"win/conflicts/incompatible_applications_updater.cc", "win/conflicts/incompatible_applications_updater.cc",
"win/conflicts/incompatible_applications_updater.h", "win/conflicts/incompatible_applications_updater.h",
"win/conflicts/installed_applications.cc", "win/conflicts/installed_applications.cc",
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/location.h" #include "base/location.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
#include "base/win/atl.h" #include "base/win/atl.h"
#include "base/win/scoped_bstr.h" #include "base/win/scoped_bstr.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
#include "chrome/browser/google/switches.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "chrome/install_static/install_util.h" #include "chrome/install_static/install_util.h"
...@@ -48,6 +50,11 @@ ...@@ -48,6 +50,11 @@
namespace { namespace {
struct UpdateCheckResult {
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
HRESULT hresult = S_OK;
};
// The status of the upgrade. These values are used for a histogram. Do not // The status of the upgrade. These values are used for a histogram. Do not
// reorder. // reorder.
enum GoogleUpdateUpgradeStatus { enum GoogleUpdateUpgradeStatus {
...@@ -202,6 +209,35 @@ base::Optional<UpdateState>* GetLastUpdateStateStorage() { ...@@ -202,6 +209,35 @@ base::Optional<UpdateState>* GetLastUpdateStateStorage() {
return storage.get(); return storage.get();
} }
// Checks if --simulate-update-hresult is present in the command line and
// returns either: nullopt if switch not present, or E_FAIL if the switch
// was present without the value, or the value of the switch as an HRESULT.
// Additionally the returned structure contains the default error code
// GOOGLE_UPDATE_ERROR_UPDATING or the value of --simulate-update-error-code.
base::Optional<UpdateCheckResult> GetSimulatedErrorForDebugging() {
const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
if (!cmd_line.HasSwitch(switches::kSimulateUpdateHresult))
return base::nullopt;
uint32_t error_from_string = 0;
std::string error_switch_value =
cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateHresult);
HRESULT hresult = E_FAIL;
if (base::HexStringToUInt(error_switch_value, &error_from_string))
hresult = error_from_string;
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_ERROR_UPDATING;
error_switch_value =
cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateErrorCode);
int32_t error_code_value = 0;
if (base::StringToInt(error_switch_value, &error_code_value) &&
error_code_value >= 0 && error_code_value < NUM_ERROR_CODES) {
error_code = static_cast<GoogleUpdateErrorCode>(error_code_value);
}
return {{error_code, hresult}};
}
// UpdateCheckDriver ----------------------------------------------------------- // UpdateCheckDriver -----------------------------------------------------------
// A driver that is created and destroyed on the caller's thread and drives // A driver that is created and destroyed on the caller's thread and drives
...@@ -241,20 +277,18 @@ class UpdateCheckDriver { ...@@ -241,20 +277,18 @@ class UpdateCheckDriver {
// Starts an update check. // Starts an update check.
void BeginUpdateCheck(); void BeginUpdateCheck();
// Returns the result of initiating an update check. Sets |error_code| if the // Returns the result of initiating an update check. On failure, the instance
// result is any kind of failure. On failure, the instance is left in a // is left in a consistent state so that this method can be invoked later to
// consistent state so that this method can be invoked later to retry the // retry the steps that failed.
// steps that failed. UpdateCheckResult BeginUpdateCheckInternal();
HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
// Sets status_ to UPGRADE_ERROR, update_state_.error_code to |error_code|, // Sets status_ to UPGRADE_ERROR, update_state_.error_code to |error_code|,
// update_state_.hresult to |hresult|, update_state_.installer_exit_code to // update_state_.hresult to |check_result.hresult|,
// |installer_exit_code|, and html_error_message_ to a composition of all // update_state_.installer_exit_code to |installer_exit_code|,
// values suitable for display to the user. This call should be followed by // and html_error_message_ to a composition of all values suitable for display
// deletion of the driver, which will result in callers being notified via // to the user. This call should be followed by deletion of the driver, which
// their delegates. // will result in callers being notified via their delegates.
void OnUpgradeError(GoogleUpdateErrorCode error_code, void OnUpgradeError(UpdateCheckResult check_result,
HRESULT hresult,
base::Optional<int> installer_exit_code, base::Optional<int> installer_exit_code,
const base::string16& error_string); const base::string16& error_string);
...@@ -467,16 +501,15 @@ void UpdateCheckDriver::NotifyUpgradeProgress( ...@@ -467,16 +501,15 @@ void UpdateCheckDriver::NotifyUpgradeProgress(
} }
void UpdateCheckDriver::BeginUpdateCheck() { void UpdateCheckDriver::BeginUpdateCheck() {
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR; UpdateCheckResult result = BeginUpdateCheckInternal();
HRESULT hresult = BeginUpdateCheckInternal(&error_code); if (SUCCEEDED(result.hresult)) {
if (SUCCEEDED(hresult)) {
// Start polling. // Start polling.
task_runner_->PostTask(FROM_HERE, task_runner_->PostTask(FROM_HERE,
base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate, base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate,
base::Unretained(this))); base::Unretained(this)));
return; return;
} }
if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) { if (result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
// This particular transient error is worth retrying. // This particular transient error is worth retrying.
if (allowed_retries_) { if (allowed_retries_) {
--allowed_retries_; --allowed_retries_;
...@@ -489,14 +522,18 @@ void UpdateCheckDriver::BeginUpdateCheck() { ...@@ -489,14 +522,18 @@ void UpdateCheckDriver::BeginUpdateCheck() {
} }
} }
DCHECK(FAILED(hresult)); DCHECK(FAILED(result.hresult));
OnUpgradeError(error_code, hresult, base::nullopt, base::string16()); OnUpgradeError(result, base::nullopt, base::string16());
result_runner_->DeleteSoon(FROM_HERE, this); result_runner_->DeleteSoon(FROM_HERE, this);
} }
HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( UpdateCheckResult UpdateCheckDriver::BeginUpdateCheckInternal() {
GoogleUpdateErrorCode* error_code) { const auto simulated_error = GetSimulatedErrorForDebugging();
if (simulated_error.has_value())
return simulated_error.value();
HRESULT hresult = S_OK; HRESULT hresult = S_OK;
// Instantiate GoogleUpdate3Web{Machine,User}Class. // Instantiate GoogleUpdate3Web{Machine,User}Class.
if (!google_update_) { if (!google_update_) {
base::FilePath chrome_exe; base::FilePath chrome_exe;
...@@ -508,23 +545,23 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( ...@@ -508,23 +545,23 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
// Make sure ATL is initialized in this module. // Make sure ATL is initialized in this module.
ui::win::CreateATLModuleIfNeeded(); ui::win::CreateATLModuleIfNeeded();
*error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_); const GoogleUpdateErrorCode error_code =
if (*error_code != GOOGLE_UPDATE_NO_ERROR) CanUpdateCurrentChrome(chrome_exe, system_level_install_);
return E_FAIL; if (error_code != GOOGLE_UPDATE_NO_ERROR)
return {error_code, E_FAIL};
hresult = CreateGoogleUpdate3WebClass(system_level_install_, hresult = CreateGoogleUpdate3WebClass(system_level_install_,
install_update_if_possible_, install_update_if_possible_,
elevation_window_, &google_update_); elevation_window_, &google_update_);
if (FAILED(hresult)) { if (FAILED(hresult))
*error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; return {GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hresult};
return hresult;
}
ConfigureProxyBlanket(google_update_.Get()); ConfigureProxyBlanket(google_update_.Get());
} }
// The class was created, so all subsequent errors are reported as: // The class was created, so all subsequent errors are reported as:
*error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; constexpr GoogleUpdateErrorCode error_code =
GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
// Create an app bundle. // Create an app bundle.
if (!app_bundle_) { if (!app_bundle_) {
...@@ -532,10 +569,10 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( ...@@ -532,10 +569,10 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
Microsoft::WRL::ComPtr<IDispatch> dispatch; Microsoft::WRL::ComPtr<IDispatch> dispatch;
hresult = google_update_->createAppBundleWeb(dispatch.GetAddressOf()); hresult = google_update_->createAppBundleWeb(dispatch.GetAddressOf());
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
hresult = dispatch.CopyTo(app_bundle.GetAddressOf()); hresult = dispatch.CopyTo(app_bundle.GetAddressOf());
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
dispatch.Reset(); dispatch.Reset();
ConfigureProxyBlanket(app_bundle.Get()); ConfigureProxyBlanket(app_bundle.Get());
...@@ -550,7 +587,7 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( ...@@ -550,7 +587,7 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
hresult = app_bundle->initialize(); hresult = app_bundle->initialize();
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
if (elevation_window_) { if (elevation_window_) {
// Likewise, a failure to set the parent window need not block an update // Likewise, a failure to set the parent window need not block an update
// check. // check.
...@@ -572,27 +609,27 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( ...@@ -572,27 +609,27 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
hresult = hresult =
app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid).Get()); app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid).Get());
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
// Move the IAppBundleWeb reference into a local now so that failures from // Move the IAppBundleWeb reference into a local now so that failures from
// this point onward result in it being released. // this point onward result in it being released.
Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle; Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle;
app_bundle.Swap(app_bundle_); app_bundle.Swap(app_bundle_);
hresult = app_bundle->get_appWeb(0, dispatch.GetAddressOf()); hresult = app_bundle->get_appWeb(0, dispatch.GetAddressOf());
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
Microsoft::WRL::ComPtr<IAppWeb> app; Microsoft::WRL::ComPtr<IAppWeb> app;
hresult = dispatch.CopyTo(app.GetAddressOf()); hresult = dispatch.CopyTo(app.GetAddressOf());
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
ConfigureProxyBlanket(app.Get()); ConfigureProxyBlanket(app.Get());
hresult = app_bundle->checkForUpdate(); hresult = app_bundle->checkForUpdate();
if (FAILED(hresult)) if (FAILED(hresult))
return hresult; return {error_code, hresult};
app_bundle_.Swap(app_bundle); app_bundle_.Swap(app_bundle);
app_.Swap(app); app_.Swap(app);
} }
return hresult; return {GOOGLE_UPDATE_NO_ERROR, hresult};
} }
bool UpdateCheckDriver::GetCurrentState( bool UpdateCheckDriver::GetCurrentState(
...@@ -784,11 +821,11 @@ void UpdateCheckDriver::PollGoogleUpdate() { ...@@ -784,11 +821,11 @@ void UpdateCheckDriver::PollGoogleUpdate() {
int progress = 0; int progress = 0;
if (!GetCurrentState(&state, &state_value, &hresult)) { if (!GetCurrentState(&state, &state_value, &hresult)) {
OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, OnUpgradeError({GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult},
base::nullopt, base::string16()); base::nullopt, base::string16());
} else if (IsErrorState(state, state_value, &error_code, &hresult, } else if (IsErrorState(state, state_value, &error_code, &hresult,
&installer_exit_code, &error_string)) { &installer_exit_code, &error_string)) {
OnUpgradeError(error_code, hresult, installer_exit_code, error_string); OnUpgradeError({error_code, hresult}, installer_exit_code, error_string);
} else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) { } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
status_ = upgrade_status; status_ = upgrade_status;
update_state_.error_code = GOOGLE_UPDATE_NO_ERROR; update_state_.error_code = GOOGLE_UPDATE_NO_ERROR;
...@@ -835,17 +872,16 @@ void UpdateCheckDriver::PollGoogleUpdate() { ...@@ -835,17 +872,16 @@ void UpdateCheckDriver::PollGoogleUpdate() {
result_runner_->DeleteSoon(FROM_HERE, this); result_runner_->DeleteSoon(FROM_HERE, this);
} }
void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, void UpdateCheckDriver::OnUpgradeError(UpdateCheckResult check_result,
HRESULT hresult,
base::Optional<int> installer_exit_code, base::Optional<int> installer_exit_code,
const base::string16& error_string) { const base::string16& error_string) {
status_ = UPGRADE_ERROR; status_ = UPGRADE_ERROR;
update_state_.error_code = error_code; update_state_.error_code = check_result.error_code;
update_state_.hresult = hresult; update_state_.hresult = check_result.hresult;
update_state_.installer_exit_code = installer_exit_code; update_state_.installer_exit_code = installer_exit_code;
// Some specific result codes have dedicated messages. // Some specific result codes have dedicated messages.
if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) { if (check_result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
html_error_message_ = l10n_util::GetStringUTF16( html_error_message_ = l10n_util::GetStringUTF16(
IDS_ABOUT_BOX_EXTERNAL_UPDATE_IS_RUNNING); IDS_ABOUT_BOX_EXTERNAL_UPDATE_IS_RUNNING);
return; return;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_path_override.h" #include "base/test/scoped_path_override.h"
#include "base/test/test_reg_util_win.h" #include "base/test/test_reg_util_win.h"
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#include "base/version.h" #include "base/version.h"
#include "base/win/atl.h" #include "base/win/atl.h"
#include "base/win/registry.h" #include "base/win/registry.h"
#include "chrome/browser/google/switches.h"
#include "chrome/common/chrome_version.h" #include "chrome/common/chrome_version.h"
#include "chrome/install_static/test/scoped_install_details.h" #include "chrome/install_static/test/scoped_install_details.h"
#include "chrome/installer/util/google_update_settings.h" #include "chrome/installer/util/google_update_settings.h"
...@@ -35,6 +37,8 @@ ...@@ -35,6 +37,8 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/win/atl_module.h" #include "ui/base/win/atl_module.h"
using ::testing::_;
using ::testing::AllOfArray;
using ::testing::DoAll; using ::testing::DoAll;
using ::testing::HasSubstr; using ::testing::HasSubstr;
using ::testing::InSequence; using ::testing::InSequence;
...@@ -45,7 +49,6 @@ using ::testing::SetArgPointee; ...@@ -45,7 +49,6 @@ using ::testing::SetArgPointee;
using ::testing::StrEq; using ::testing::StrEq;
using ::testing::StrictMock; using ::testing::StrictMock;
using ::testing::Values; using ::testing::Values;
using ::testing::_;
namespace { namespace {
...@@ -1062,6 +1065,72 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) { ...@@ -1062,6 +1065,72 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) {
EXPECT_EQ(GetLastUpdateState()->new_version, new_version_); EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
} }
// Test the case where the GoogleUpdate class responds with error provided
// via the command line with specified hresult and GoogleUpdateErrorCode.
TEST_P(GoogleUpdateWinTest, SimulateHresultWithErrorCode) {
base::test::ScopedCommandLine commandline;
// Simulate GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND (3).
commandline.GetProcessCommandLine()->AppendSwitchASCII(
switches::kSimulateUpdateErrorCode, "3");
// Simulate WININET_E_INCORRECT_HANDLE_TYPE (0x80072ef2).
commandline.GetProcessCommandLine()->AppendSwitchASCII(
switches::kSimulateUpdateHresult, "0x80072ef2");
// Expect the appropriate error when the on-demand class cannot be created.
EXPECT_CALL(mock_update_check_delegate_,
OnError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND,
AllOfArray({HasSubstr(L"error code 3:"),
HasSubstr(L"0x80072EF2")}),
_));
BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND);
}
// Test the case where the GoogleUpdate class responds with error provided
// via the command line with a specific hresult.
TEST_P(GoogleUpdateWinTest, SimulateHresultOnly) {
base::test::ScopedCommandLine commandline;
// Simulate WININET_E_INCORRECT_HANDLE_TYPE (0x80072ef2).
commandline.GetProcessCommandLine()->AppendSwitchASCII(
switches::kSimulateUpdateHresult, "0x80072ef2");
// Expect the appropriate error when the on-demand class cannot be created.
EXPECT_CALL(mock_update_check_delegate_,
OnError(GOOGLE_UPDATE_ERROR_UPDATING,
AllOfArray({HasSubstr(L"error code 7:"),
HasSubstr(L"0x80072EF2")}),
_));
BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_ERROR_UPDATING);
}
// Test the case where the GoogleUpdate class responds with error provided
// via the command line without specific hresult.
TEST_P(GoogleUpdateWinTest, SimulateHresultDefault) {
base::test::ScopedCommandLine commandline;
commandline.GetProcessCommandLine()->AppendSwitch(
switches::kSimulateUpdateHresult);
// Expect the appropriate error when the on-demand class cannot be created.
EXPECT_CALL(mock_update_check_delegate_,
OnError(GOOGLE_UPDATE_ERROR_UPDATING,
AllOfArray({HasSubstr(L"error code 7:"),
HasSubstr(L"0x80004005")}),
_));
BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_ERROR_UPDATING);
}
INSTANTIATE_TEST_SUITE_P(UserLevel, GoogleUpdateWinTest, Values(false)); INSTANTIATE_TEST_SUITE_P(UserLevel, GoogleUpdateWinTest, Values(false));
INSTANTIATE_TEST_SUITE_P(SystemLevel, GoogleUpdateWinTest, Values(true)); INSTANTIATE_TEST_SUITE_P(SystemLevel, GoogleUpdateWinTest, Values(true));
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/google/switches.h"
namespace switches {
// Simulates a specific HRESULT error code returned by the update check.
// If the switch value is not specified (as hex) then it defaults to E_FAIL.
const char kSimulateUpdateHresult[] = "simulate-update-hresult";
// Simulates a GoogleUpdateErrorCode error by the update check.
// Must be supplied with |kSimulateUpdateHresult| switch.
const char kSimulateUpdateErrorCode[] = "simulate-update-error-code";
} // namespace switches
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_GOOGLE_SWITCHES_H_
#define CHROME_BROWSER_GOOGLE_SWITCHES_H_
namespace switches {
extern const char kSimulateUpdateHresult[];
extern const char kSimulateUpdateErrorCode[];
} // namespace switches
#endif // CHROME_BROWSER_GOOGLE_SWITCHES_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment