Fix Handoff from Omaha to O4 fails
The updater scope was not taking the legacy command line format into account, now fixed by determining the scope using the legacy-compatible command line. Added integration tests. Bug: 1379746 Change-Id: I42386daf3276156ab34e6ac17094b0b6439a8898 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4111693 Reviewed-by: Sorin Jianu <sorin@chromium.org> Commit-Queue: Sorin Jianu <sorin@chromium.org> Commit-Queue: S Ganesh <ganesh@chromium.org> Auto-Submit: S Ganesh <ganesh@chromium.org> Cr-Commit-Position: refs/heads/main@{#1084071}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
d1d8d7bee4
commit
1b1e771923
@@ -46,6 +46,11 @@ class IntegrationTestCommands
|
|||||||
const std::string& install_data_index,
|
const std::string& install_data_index,
|
||||||
const base::Version& from_version,
|
const base::Version& from_version,
|
||||||
const base::Version& to_version) const = 0;
|
const base::Version& to_version) const = 0;
|
||||||
|
virtual void ExpectInstallSequence(ScopedServer* test_server,
|
||||||
|
const std::string& app_id,
|
||||||
|
const std::string& install_data_index,
|
||||||
|
const base::Version& from_version,
|
||||||
|
const base::Version& to_version) const = 0;
|
||||||
virtual void ExpectVersionActive(const std::string& version) const = 0;
|
virtual void ExpectVersionActive(const std::string& version) const = 0;
|
||||||
virtual void ExpectVersionNotActive(const std::string& version) const = 0;
|
virtual void ExpectVersionNotActive(const std::string& version) const = 0;
|
||||||
virtual void Uninstall() const = 0;
|
virtual void Uninstall() const = 0;
|
||||||
@@ -90,6 +95,7 @@ class IntegrationTestCommands
|
|||||||
virtual void RunUninstallCmdLine() const = 0;
|
virtual void RunUninstallCmdLine() const = 0;
|
||||||
virtual void SetUpTestService() const = 0;
|
virtual void SetUpTestService() const = 0;
|
||||||
virtual void TearDownTestService() const = 0;
|
virtual void TearDownTestService() const = 0;
|
||||||
|
virtual void RunHandoff(const std::string& app_id) const = 0;
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
virtual void StressUpdateService() const = 0;
|
virtual void StressUpdateService() const = 0;
|
||||||
virtual void CallServiceUpdate(const std::string& app_id,
|
virtual void CallServiceUpdate(const std::string& app_id,
|
||||||
|
@@ -102,6 +102,16 @@ class IntegrationTestCommandsSystem : public IntegrationTestCommands {
|
|||||||
to_version);
|
to_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpectInstallSequence(ScopedServer* test_server,
|
||||||
|
const std::string& app_id,
|
||||||
|
const std::string& install_data_index,
|
||||||
|
const base::Version& from_version,
|
||||||
|
const base::Version& to_version) const override {
|
||||||
|
updater::test::ExpectInstallSequence(updater_scope_, test_server, app_id,
|
||||||
|
install_data_index, from_version,
|
||||||
|
to_version);
|
||||||
|
}
|
||||||
|
|
||||||
void ExpectVersionActive(const std::string& version) const override {
|
void ExpectVersionActive(const std::string& version) const override {
|
||||||
RunCommand("expect_version_active", {Param("version", version)});
|
RunCommand("expect_version_active", {Param("version", version)});
|
||||||
}
|
}
|
||||||
@@ -251,6 +261,10 @@ class IntegrationTestCommandsSystem : public IntegrationTestCommands {
|
|||||||
void TearDownTestService() const override {
|
void TearDownTestService() const override {
|
||||||
updater::test::RunTestServiceCommand("teardown");
|
updater::test::RunTestServiceCommand("teardown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunHandoff(const std::string& app_id) const override {
|
||||||
|
RunCommand("run_handoff", {Param("app_id", app_id)});
|
||||||
|
}
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
|
|
||||||
base::FilePath GetDifferentUserPath() const override {
|
base::FilePath GetDifferentUserPath() const override {
|
||||||
|
@@ -83,6 +83,16 @@ class IntegrationTestCommandsUser : public IntegrationTestCommands {
|
|||||||
to_version);
|
to_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpectInstallSequence(ScopedServer* test_server,
|
||||||
|
const std::string& app_id,
|
||||||
|
const std::string& install_data_index,
|
||||||
|
const base::Version& from_version,
|
||||||
|
const base::Version& to_version) const override {
|
||||||
|
updater::test::ExpectInstallSequence(updater_scope_, test_server, app_id,
|
||||||
|
install_data_index, from_version,
|
||||||
|
to_version);
|
||||||
|
}
|
||||||
|
|
||||||
void ExpectVersionActive(const std::string& version) const override {
|
void ExpectVersionActive(const std::string& version) const override {
|
||||||
updater::test::ExpectVersionActive(updater_scope_, version);
|
updater::test::ExpectVersionActive(updater_scope_, version);
|
||||||
}
|
}
|
||||||
@@ -218,6 +228,10 @@ class IntegrationTestCommandsUser : public IntegrationTestCommands {
|
|||||||
void SetUpTestService() const override {}
|
void SetUpTestService() const override {}
|
||||||
|
|
||||||
void TearDownTestService() const override {}
|
void TearDownTestService() const override {}
|
||||||
|
|
||||||
|
void RunHandoff(const std::string& app_id) const override {
|
||||||
|
updater::test::RunHandoff(updater_scope_, app_id);
|
||||||
|
}
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
|
|
||||||
base::FilePath GetDifferentUserPath() const override {
|
base::FilePath GetDifferentUserPath() const override {
|
||||||
|
@@ -194,6 +194,10 @@ class IntegrationTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunUninstallCmdLine() { test_commands_->RunUninstallCmdLine(); }
|
void RunUninstallCmdLine() { test_commands_->RunUninstallCmdLine(); }
|
||||||
|
|
||||||
|
void RunHandoff(const std::string& app_id) {
|
||||||
|
test_commands_->RunHandoff(app_id);
|
||||||
|
}
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
|
|
||||||
void SetupFakeUpdaterHigherVersion() {
|
void SetupFakeUpdaterHigherVersion() {
|
||||||
@@ -308,14 +312,13 @@ class IntegrationTest : public ::testing::Test {
|
|||||||
test_commands_->ExpectSelfUpdateSequence(test_server);
|
test_commands_->ExpectSelfUpdateSequence(test_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpectInstallEvent(ScopedServer* test_server,
|
void ExpectInstallSequence(ScopedServer* test_server,
|
||||||
const std::string& app_id) {
|
const std::string& app_id,
|
||||||
test_server->ExpectOnce(
|
const std::string& install_data_index,
|
||||||
{base::BindRepeating(
|
const base::Version& from_version,
|
||||||
RequestMatcherRegex,
|
const base::Version& to_version) {
|
||||||
base::StrCat({R"(.*"appid":")", app_id, R"(","enabled":true,")",
|
test_commands_->ExpectInstallSequence(
|
||||||
R"(event":\[{"eventresult":1,"eventtype":2,.*)"}))},
|
test_server, app_id, install_data_index, from_version, to_version);
|
||||||
"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StressUpdateService() { test_commands_->StressUpdateService(); }
|
void StressUpdateService() { test_commands_->StressUpdateService(); }
|
||||||
@@ -561,6 +564,21 @@ TEST_F(IntegrationTest, UpdateApp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
TEST_F(IntegrationTest, Handoff) {
|
||||||
|
ScopedServer test_server(test_commands_);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(Install());
|
||||||
|
|
||||||
|
const std::string kAppId("test");
|
||||||
|
const base::Version v1("1");
|
||||||
|
ExpectInstallSequence(&test_server, kAppId, "", base::Version({0, 0, 0, 0}),
|
||||||
|
v1);
|
||||||
|
RunHandoff(kAppId);
|
||||||
|
EXPECT_TRUE(WaitForUpdaterExit());
|
||||||
|
ExpectAppVersion(kAppId, v1);
|
||||||
|
|
||||||
|
Uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ForceInstallApp) {
|
TEST_F(IntegrationTest, ForceInstallApp) {
|
||||||
ScopedServer test_server(test_commands_);
|
ScopedServer test_server(test_commands_);
|
||||||
ASSERT_NO_FATAL_FAILURE(Install());
|
ASSERT_NO_FATAL_FAILURE(Install());
|
||||||
|
@@ -273,6 +273,7 @@ void AppTestHelper::FirstTaskRun() {
|
|||||||
{"expect_legacy_policy_status_succeeds",
|
{"expect_legacy_policy_status_succeeds",
|
||||||
WithSystemScope(Wrap(&ExpectLegacyPolicyStatusSucceeds))},
|
WithSystemScope(Wrap(&ExpectLegacyPolicyStatusSucceeds))},
|
||||||
{"run_uninstall_cmd_line", WithSystemScope(Wrap(&RunUninstallCmdLine))},
|
{"run_uninstall_cmd_line", WithSystemScope(Wrap(&RunUninstallCmdLine))},
|
||||||
|
{"run_handoff", WithSwitch("app_id", WithSystemScope(Wrap(&RunHandoff)))},
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
{"expect_version_active",
|
{"expect_version_active",
|
||||||
WithSwitch("version", WithSystemScope(Wrap(&ExpectVersionActive)))},
|
WithSwitch("version", WithSystemScope(Wrap(&ExpectVersionActive)))},
|
||||||
|
@@ -194,6 +194,57 @@ void RunUpdaterWithSwitch(const base::Version& version,
|
|||||||
EXPECT_EQ(exit_code, expected_exit_code);
|
EXPECT_EQ(exit_code, expected_exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpectSequence(UpdaterScope scope,
|
||||||
|
ScopedServer* test_server,
|
||||||
|
const std::string& app_id,
|
||||||
|
const std::string& install_data_index,
|
||||||
|
int event_type,
|
||||||
|
const base::Version& from_version,
|
||||||
|
const base::Version& to_version) {
|
||||||
|
base::FilePath test_data_path;
|
||||||
|
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_path));
|
||||||
|
base::FilePath crx_path = test_data_path.Append(FILE_PATH_LITERAL("updater"))
|
||||||
|
.AppendASCII(kDoNothingCRXName);
|
||||||
|
ASSERT_TRUE(base::PathExists(crx_path));
|
||||||
|
|
||||||
|
// First request: update check.
|
||||||
|
test_server->ExpectOnce(
|
||||||
|
{base::BindRepeating(
|
||||||
|
RequestMatcherRegex,
|
||||||
|
base::StringPrintf(R"(.*"appid":"%s".*)", app_id.c_str())),
|
||||||
|
base::BindRepeating(
|
||||||
|
RequestMatcherRegex,
|
||||||
|
base::StringPrintf(
|
||||||
|
R"(.*%s)",
|
||||||
|
!install_data_index.empty()
|
||||||
|
? base::StringPrintf(
|
||||||
|
R"("data":\[{"index":"%s","name":"install"}],.*)",
|
||||||
|
install_data_index.c_str())
|
||||||
|
.c_str()
|
||||||
|
: "")),
|
||||||
|
GetScopePredicate(scope)},
|
||||||
|
GetUpdateResponse(app_id, install_data_index,
|
||||||
|
test_server->base_url().spec(), to_version, crx_path,
|
||||||
|
kDoNothingCRXRun, {}));
|
||||||
|
|
||||||
|
// Second request: update download.
|
||||||
|
std::string crx_bytes;
|
||||||
|
base::ReadFileToString(crx_path, &crx_bytes);
|
||||||
|
test_server->ExpectOnce({base::BindRepeating(RequestMatcherRegex, "")},
|
||||||
|
crx_bytes);
|
||||||
|
|
||||||
|
// Third request: event ping.
|
||||||
|
test_server->ExpectOnce(
|
||||||
|
{base::BindRepeating(
|
||||||
|
RequestMatcherRegex,
|
||||||
|
base::StringPrintf(R"(.*"eventresult":1,"eventtype":%d,)"
|
||||||
|
R"("nextversion":"%s","previousversion":"%s".*)",
|
||||||
|
event_type, to_version.GetString().c_str(),
|
||||||
|
from_version.GetString().c_str())),
|
||||||
|
GetScopePredicate(scope)},
|
||||||
|
")]}'\n");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ExitTestMode(UpdaterScope scope) {
|
void ExitTestMode(UpdaterScope scope) {
|
||||||
@@ -544,48 +595,18 @@ void ExpectUpdateSequence(UpdaterScope scope,
|
|||||||
const std::string& install_data_index,
|
const std::string& install_data_index,
|
||||||
const base::Version& from_version,
|
const base::Version& from_version,
|
||||||
const base::Version& to_version) {
|
const base::Version& to_version) {
|
||||||
base::FilePath test_data_path;
|
ExpectSequence(scope, test_server, app_id, install_data_index, 3,
|
||||||
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_path));
|
from_version, to_version);
|
||||||
base::FilePath crx_path = test_data_path.Append(FILE_PATH_LITERAL("updater"))
|
}
|
||||||
.AppendASCII(kDoNothingCRXName);
|
|
||||||
ASSERT_TRUE(base::PathExists(crx_path));
|
|
||||||
|
|
||||||
// First request: update check.
|
void ExpectInstallSequence(UpdaterScope scope,
|
||||||
test_server->ExpectOnce(
|
ScopedServer* test_server,
|
||||||
{base::BindRepeating(
|
const std::string& app_id,
|
||||||
RequestMatcherRegex,
|
const std::string& install_data_index,
|
||||||
base::StringPrintf(R"(.*"appid":"%s".*)", app_id.c_str())),
|
const base::Version& from_version,
|
||||||
base::BindRepeating(
|
const base::Version& to_version) {
|
||||||
RequestMatcherRegex,
|
ExpectSequence(scope, test_server, app_id, install_data_index, 2,
|
||||||
base::StringPrintf(
|
from_version, to_version);
|
||||||
R"(.*%s)",
|
|
||||||
!install_data_index.empty()
|
|
||||||
? base::StringPrintf(
|
|
||||||
R"("data":\[{"index":"%s","name":"install"}],.*)",
|
|
||||||
install_data_index.c_str())
|
|
||||||
.c_str()
|
|
||||||
: "")),
|
|
||||||
GetScopePredicate(scope)},
|
|
||||||
GetUpdateResponse(app_id, install_data_index,
|
|
||||||
test_server->base_url().spec(), to_version, crx_path,
|
|
||||||
kDoNothingCRXRun, {}));
|
|
||||||
|
|
||||||
// Second request: update download.
|
|
||||||
std::string crx_bytes;
|
|
||||||
base::ReadFileToString(crx_path, &crx_bytes);
|
|
||||||
test_server->ExpectOnce({base::BindRepeating(RequestMatcherRegex, "")},
|
|
||||||
crx_bytes);
|
|
||||||
|
|
||||||
// Third request: event ping.
|
|
||||||
test_server->ExpectOnce(
|
|
||||||
{base::BindRepeating(
|
|
||||||
RequestMatcherRegex,
|
|
||||||
base::StringPrintf(R"(.*"eventresult":1,"eventtype":3,)"
|
|
||||||
R"("nextversion":"%s","previousversion":"%s".*)",
|
|
||||||
to_version.GetString().c_str(),
|
|
||||||
from_version.GetString().c_str())),
|
|
||||||
GetScopePredicate(scope)},
|
|
||||||
")]}'\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs multiple cycles of instantiating the update service, calling
|
// Runs multiple cycles of instantiating the update service, calling
|
||||||
|
@@ -215,6 +215,7 @@ void InvokeTestServiceFunction(const std::string& function_name,
|
|||||||
const base::Value::Dict& arguments);
|
const base::Value::Dict& arguments);
|
||||||
|
|
||||||
void RunUninstallCmdLine(UpdaterScope scope);
|
void RunUninstallCmdLine(UpdaterScope scope);
|
||||||
|
void RunHandoff(UpdaterScope scope, const std::string& app_id);
|
||||||
#endif // BUILDFLAG(IS_WIN)
|
#endif // BUILDFLAG(IS_WIN)
|
||||||
|
|
||||||
// Returns the number of files in the directory, not including directories,
|
// Returns the number of files in the directory, not including directories,
|
||||||
@@ -234,6 +235,13 @@ void ExpectUpdateSequence(UpdaterScope scope,
|
|||||||
const base::Version& from_version,
|
const base::Version& from_version,
|
||||||
const base::Version& to_version);
|
const base::Version& to_version);
|
||||||
|
|
||||||
|
void ExpectInstallSequence(UpdaterScope scope,
|
||||||
|
ScopedServer* test_server,
|
||||||
|
const std::string& app_id,
|
||||||
|
const std::string& install_data_index,
|
||||||
|
const base::Version& from_version,
|
||||||
|
const base::Version& to_version);
|
||||||
|
|
||||||
void StressUpdateService(UpdaterScope scope);
|
void StressUpdateService(UpdaterScope scope);
|
||||||
|
|
||||||
void CallServiceUpdate(UpdaterScope updater_scope,
|
void CallServiceUpdate(UpdaterScope updater_scope,
|
||||||
@@ -259,7 +267,6 @@ void UninstallApp(UpdaterScope scope, const std::string& app_id);
|
|||||||
void RunOfflineInstall(UpdaterScope scope,
|
void RunOfflineInstall(UpdaterScope scope,
|
||||||
bool is_legacy_install,
|
bool is_legacy_install,
|
||||||
bool is_silent_install);
|
bool is_silent_install);
|
||||||
|
|
||||||
} // namespace updater::test
|
} // namespace updater::test
|
||||||
|
|
||||||
#endif // CHROME_UPDATER_TEST_INTEGRATION_TESTS_IMPL_H_
|
#endif // CHROME_UPDATER_TEST_INTEGRATION_TESTS_IMPL_H_
|
||||||
|
@@ -1410,6 +1410,27 @@ void RunUninstallCmdLine(UpdaterScope scope) {
|
|||||||
EXPECT_EQ(0, exit_code);
|
EXPECT_EQ(0, exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunHandoff(UpdaterScope scope, const std::string& app_id) {
|
||||||
|
const absl::optional<base::FilePath> installed_executable_path =
|
||||||
|
GetInstalledExecutablePath(scope);
|
||||||
|
ASSERT_TRUE(installed_executable_path);
|
||||||
|
ASSERT_TRUE(base::PathExists(*installed_executable_path));
|
||||||
|
|
||||||
|
base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait_process;
|
||||||
|
const std::wstring command_line(base::StrCat(
|
||||||
|
{installed_executable_path->value(), L" /handoff \"appguid=",
|
||||||
|
base::ASCIIToWide(app_id), L"&needsadmin=",
|
||||||
|
IsSystemInstall(scope) ? L"Prefers" : L"False", L"\" /silent"}));
|
||||||
|
VLOG(0) << " RunHandoff: " << command_line;
|
||||||
|
const base::Process process = base::LaunchProcess(command_line, {});
|
||||||
|
ASSERT_TRUE(process.IsValid());
|
||||||
|
|
||||||
|
int exit_code = 0;
|
||||||
|
ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
|
||||||
|
&exit_code));
|
||||||
|
ASSERT_EQ(exit_code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void SetupFakeLegacyUpdaterData(UpdaterScope scope) {
|
void SetupFakeLegacyUpdaterData(UpdaterScope scope) {
|
||||||
const HKEY root = UpdaterScopeToHKeyRoot(scope);
|
const HKEY root = UpdaterScopeToHKeyRoot(scope);
|
||||||
|
|
||||||
|
@@ -8,11 +8,11 @@
|
|||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "chrome/updater/constants.h"
|
#include "chrome/updater/constants.h"
|
||||||
|
#include "chrome/updater/util/util.h"
|
||||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
#include "chrome/updater/tag.h"
|
#include "chrome/updater/tag.h"
|
||||||
#include "chrome/updater/util/util.h"
|
|
||||||
#include "chrome/updater/util/win_util.h"
|
#include "chrome/updater/util/win_util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ UpdaterScope GetUpdaterScopeForCommandLine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdaterScope GetUpdaterScope() {
|
UpdaterScope GetUpdaterScope() {
|
||||||
return GetUpdaterScopeForCommandLine(*base::CommandLine::ForCurrentProcess());
|
return GetUpdaterScopeForCommandLine(GetCommandLineLegacyCompatible());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSystemInstall() {
|
bool IsSystemInstall() {
|
||||||
|
@@ -70,6 +70,10 @@ IntegrationTest.Install tests that the updater can be installed on a clean OS,
|
|||||||
that it is immediately active after installation, and then can be cleanly
|
that it is immediately active after installation, and then can be cleanly
|
||||||
uninstalled.
|
uninstalled.
|
||||||
|
|
||||||
|
IntegrationTest.Handoff tests that the updater can be installed on a clean OS,
|
||||||
|
that it can install an app via a "/handoff" command line, and then can be
|
||||||
|
cleanly uninstalled.
|
||||||
|
|
||||||
Overinstall cases are tested by IntegrationTest.OverinstallWorking and
|
Overinstall cases are tested by IntegrationTest.OverinstallWorking and
|
||||||
IntegrationTest.OverinstallBroken, to ensure that the updater can be installed
|
IntegrationTest.OverinstallBroken, to ensure that the updater can be installed
|
||||||
on an unclean OS, and as a post-condition of installation, the system has a
|
on an unclean OS, and as a post-condition of installation, the system has a
|
||||||
|
Reference in New Issue
Block a user