1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <optional>
#include <string>
#include <vector>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/process/process_iterator.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "build/branding_buildflags.h"
#include "chrome/updater/activity.h"
#include "chrome/updater/activity_impl_util_posix.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/external_constants_builder.h"
#include "chrome/updater/linux/systemd_util.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/service_proxy_factory.h"
#include "chrome/updater/test/integration_tests_impl.h"
#include "chrome/updater/test/unit_test_util.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/updater_branding.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/linux_util.h"
#include "chrome/updater/util/posix_util.h"
#include "chrome/updater/util/util.h"
#include "components/crx_file/crx_verifier.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace updater::test {
namespace {
base::FilePath GetExecutablePath() {
base::FilePath out_dir;
if (!base::PathService::Get(base::DIR_EXE, &out_dir)) {
return base::FilePath();
}
return out_dir.Append(GetExecutableRelativePath());
}
} // namespace
std::optional<base::FilePath> GetFakeUpdaterInstallFolderPath(
UpdaterScope scope,
const base::Version& version) {
return GetVersionedInstallDirectory(scope, version);
}
base::FilePath GetSetupExecutablePath() {
// There is no metainstaller on Linux, use the main executable for setup.
return GetExecutablePath();
}
std::optional<base::FilePath> GetInstalledExecutablePath(UpdaterScope scope) {
std::optional<base::FilePath> path = GetVersionedInstallDirectory(scope);
if (!path) {
return std::nullopt;
}
return path->Append(GetExecutableRelativePath());
}
bool WaitForUpdaterExit() {
const std::set<base::FilePath::StringType> process_names =
GetTestProcessNames();
return WaitFor(
[&] {
return std::ranges::none_of(process_names,
[](const auto& process_name) {
return IsProcessRunning(process_name);
});
},
[] { VLOG(0) << "Still waiting for updater to exit..."; });
}
void Uninstall(UpdaterScope scope) {
std::optional<base::FilePath> path = GetExecutablePath();
ASSERT_TRUE(path);
base::CommandLine command_line(*path);
command_line.AppendSwitch(kUninstallSwitch);
int exit_code = -1;
Run(scope, command_line, &exit_code);
EXPECT_EQ(exit_code, 0);
}
void ExpectCandidateUninstalled(UpdaterScope scope) {
std::optional<base::FilePath> path = GetVersionedInstallDirectory(scope);
ASSERT_TRUE(path);
ASSERT_TRUE(WaitFor(
[&] { return !base::PathExists(*path); },
[] { VLOG(0) << "Waiting for the candidate to be uninstalled."; }));
}
void ExpectInstalled(UpdaterScope scope) {
std::optional<base::FilePath> path = GetInstalledExecutablePath(scope);
EXPECT_TRUE(path);
if (path) {
EXPECT_TRUE(base::PathExists(*path));
}
}
void Clean(UpdaterScope scope) {
std::optional<base::FilePath> path = GetInstallDirectory(scope);
EXPECT_TRUE(path);
if (path) {
EXPECT_TRUE(base::DeletePathRecursively(*path));
}
EXPECT_TRUE(UninstallSystemdUnits(scope));
if (IsSystemInstall(scope)) {
ASSERT_NO_FATAL_FAILURE(UninstallEnterpriseCompanionApp());
}
}
// The uninstaller cannot reliably completely remove the installer directory
// itself, because it uses the prefs file and writes the log file while it
// is operating. If the provided path exists, it must be a directory with
// only these residual files present to be considered "clean".
void ExpectMostlyClean(std::optional<base::FilePath> path) {
EXPECT_TRUE(path);
if (!path || !base::PathExists(*path)) {
return;
}
// If the path exists, expect only the log and prefs files to be present.
int count = CountDirectoryFiles(*path);
EXPECT_LE(count, 2);
if (count >= 1) {
EXPECT_TRUE(base::PathExists(path->Append("updater.log")));
}
if (count == 2) {
EXPECT_TRUE(base::PathExists(path->Append("prefs.json")));
}
}
void ExpectClean(UpdaterScope scope) {
ExpectCleanProcesses();
ExpectMostlyClean(GetInstallDirectory(scope));
EXPECT_FALSE(SystemdUnitsInstalled(scope));
ASSERT_NO_FATAL_FAILURE(ExpectEnterpriseCompanionAppNotInstalled());
}
base::TimeDelta GetOverinstallTimeoutForEnterTestMode() {
return TestTimeouts::action_timeout();
}
void SetActive(UpdaterScope scope, const std::string& app_id) {
const std::optional<base::FilePath> path =
GetActiveFile(base::GetHomeDir(), app_id);
ASSERT_TRUE(path);
base::File::Error err = base::File::FILE_OK;
EXPECT_TRUE(base::CreateDirectoryAndGetError(path->DirName(), &err))
<< "Error: " << err;
EXPECT_TRUE(base::WriteFile(*path, ""));
}
void ExpectActive(UpdaterScope scope, const std::string& app_id) {
const std::optional<base::FilePath> path =
GetActiveFile(base::GetHomeDir(), app_id);
ASSERT_TRUE(path);
EXPECT_TRUE(base::PathExists(*path));
EXPECT_TRUE(base::PathIsWritable(*path));
}
void ExpectNotActive(UpdaterScope scope, const std::string& app_id) {
const std::optional<base::FilePath> path =
GetActiveFile(base::GetHomeDir(), app_id);
ASSERT_TRUE(path);
EXPECT_FALSE(base::PathExists(*path));
EXPECT_FALSE(base::PathIsWritable(*path));
}
std::vector<TestUpdaterVersion> GetRealUpdaterLowerVersions(
const std::string& arch_suffix) {
base::FilePath exe_path;
EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path));
base::FilePath old_updater_path =
exe_path.Append(FILE_PATH_LITERAL("old_updater"))
.Append(base::StrCat({base::ToLowerASCII(BROWSER_NAME_STRING),
"_linux64", arch_suffix}));
#if BUILDFLAG(CHROMIUM_BRANDING) || BUILDFLAG(GOOGLE_CHROME_BRANDING)
old_updater_path = old_updater_path.Append("cipd");
#endif
// Linux currently does not have a way to get version information for the
// executable via `FileVersionInfo`.
return {{old_updater_path.Append(
base::StrCat({kExecutableName, kExecutableSuffix})),
{}}};
}
void SetupFakeLegacyUpdater(UpdaterScope scope) {
// No legacy migration for Linux.
}
void ExpectLegacyUpdaterMigrated(UpdaterScope scope) {
// No legacy migration for Linux.
}
void InstallApp(UpdaterScope scope,
const std::string& app_id,
const base::Version& version) {
RegistrationRequest registration;
registration.app_id = app_id;
registration.version = version;
RegisterApp(scope, registration);
}
void UninstallApp(UpdaterScope scope, const std::string& app_id) {
// This can probably be combined with mac into integration_tests_posix.cc.
const base::FilePath& install_path =
base::MakeRefCounted<PersistedData>(
scope, CreateGlobalPrefs(scope)->GetPrefService(), nullptr)
->GetExistenceCheckerPath(app_id);
VLOG(1) << "Deleting app install path: " << install_path;
base::DeletePathRecursively(install_path);
SetExistenceCheckerPath(scope, app_id,
base::FilePath(FILE_PATH_LITERAL("NONE")));
}
base::CommandLine MakeElevated(base::CommandLine command_line) {
command_line.PrependWrapper("/usr/bin/sudo");
return command_line;
}
void SetPlatformPolicies(const base::Value::Dict& values) {}
void ExpectAppVersion(UpdaterScope scope,
const std::string& app_id,
const base::Version& version) {
const base::Version app_version =
base::MakeRefCounted<PersistedData>(
scope, CreateGlobalPrefs(scope)->GetPrefService(), nullptr)
->GetProductVersion(app_id);
EXPECT_TRUE(app_version.IsValid());
EXPECT_EQ(version, app_version);
}
void SetAppAllowsUsageStats(UpdaterScope scope,
const std::string& identifier,
bool allowed) {
ADD_FAILURE() << "Usage statistics are not supported on Linux.";
}
void ClearAppAllowsUsageStats(UpdaterScope scope,
const std::string& identifier) {
ADD_FAILURE() << "Usage statistics are not supported on Linux.";
}
} // namespace updater::test
|