blob: de2cdcffebed4fdaf903001e8436eff1608b042b [file] [log] [blame]
Joshua Pawlickibae1c6d2352020-03-19 19:21:441// Copyright 2020 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.
4
Mila Greena3991ae2020-10-16 00:10:555#include <stdint.h>
Joshua Pawlicki6867d7c2021-01-06 15:51:096#include <string>
Adam Norberg14b66a12021-01-20 21:54:037#include <vector>
Mila Greena3991ae2020-10-16 00:10:558
Joshua Pawlickibae1c6d2352020-03-19 19:21:449#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/files/file_util.h"
Mila Greenf6d82f82021-03-05 22:14:2912#include "base/logging.h"
Joshua Pawlickibae1c6d2352020-03-19 19:21:4413#include "base/mac/foundation_util.h"
Joshua Pawlickibae1c6d2352020-03-19 19:21:4414#include "base/path_service.h"
Joshua Pawlickia6f88e22021-05-06 14:50:1215#include "base/process/launch.h"
Joshua Pawlickicd6925c92020-12-15 15:07:5016#include "base/run_loop.h"
17#include "base/strings/sys_string_conversions.h"
18#include "base/test/bind.h"
Joshua Pawlickia6f88e22021-05-06 14:50:1219#include "base/test/test_timeouts.h"
20#include "base/time/time.h"
Mila Greena3991ae2020-10-16 00:10:5521#include "base/version.h"
Joshua Pawlicki8f755d382020-03-20 19:51:1022#include "chrome/common/mac/launchd.h"
Mila Green8ddc4e02020-05-01 00:15:0223#include "chrome/updater/constants.h"
Adam Norberg14b66a12021-01-20 21:54:0324#include "chrome/updater/external_constants_builder.h"
Joshua Pawlickicd6925c92020-12-15 15:07:5025#include "chrome/updater/launchd_util.h"
Mila Greenf6d82f82021-03-05 22:14:2926#import "chrome/updater/mac/mac_util.h"
Joshua Pawlicki8f755d382020-03-20 19:51:1027#include "chrome/updater/mac/xpc_service_names.h"
Mila Greena3991ae2020-10-16 00:10:5528#include "chrome/updater/prefs.h"
Mila Green3c9375d2021-03-17 16:33:5929#include "chrome/updater/test/integration_tests_impl.h"
Mila Green3e3058a2020-08-27 16:59:2730#include "chrome/updater/test/test_app/constants.h"
31#include "chrome/updater/test/test_app/test_app_version.h"
Mila Greenaff086902021-01-07 22:00:5232#include "chrome/updater/updater_branding.h"
Mila Greenf6d82f82021-03-05 22:14:2933#include "chrome/updater/updater_scope.h"
Joshua Pawlicki4abd1322020-08-19 22:05:5734#include "chrome/updater/util.h"
Joshua Pawlickibae1c6d2352020-03-19 19:21:4435#include "testing/gtest/include/gtest/gtest.h"
Anton Bikineev46bbb972021-05-15 17:53:5336#include "third_party/abseil-cpp/absl/types/optional.h"
Joshua Pawlicki6867d7c2021-01-06 15:51:0937#include "url/gurl.h"
Joshua Pawlickibae1c6d2352020-03-19 19:21:4438
39namespace updater {
Joshua Pawlickibae1c6d2352020-03-19 19:21:4440namespace test {
41
42namespace {
43
Mila Greenf6d82f82021-03-05 22:14:2944Launchd::Domain LaunchdDomain(UpdaterScope scope) {
45 switch (scope) {
46 case UpdaterScope::kSystem:
47 return Launchd::Domain::Local;
48 case UpdaterScope::kUser:
49 return Launchd::Domain::User;
50 }
51}
Joshua Pawlickicd6925c92020-12-15 15:07:5052
Mila Greenf6d82f82021-03-05 22:14:2953Launchd::Type LaunchdType(UpdaterScope scope) {
54 switch (scope) {
55 case UpdaterScope::kSystem:
56 return Launchd::Type::Daemon;
57 case UpdaterScope::kUser:
58 return Launchd::Type::Agent;
59 }
Joshua Pawlickicd6925c92020-12-15 15:07:5060}
61
Joshua Pawlickibae1c6d2352020-03-19 19:21:4462base::FilePath GetExecutablePath() {
63 base::FilePath test_executable;
64 if (!base::PathService::Get(base::FILE_EXE, &test_executable))
65 return base::FilePath();
66 return test_executable.DirName()
Mila Greena3991ae2020-10-16 00:10:5567 .Append(FILE_PATH_LITERAL(PRODUCT_FULLNAME_STRING ".app"))
Joshua Pawlickibae1c6d2352020-03-19 19:21:4468 .Append(FILE_PATH_LITERAL("Contents"))
69 .Append(FILE_PATH_LITERAL("MacOS"))
70 .Append(FILE_PATH_LITERAL(PRODUCT_FULLNAME_STRING));
71}
72
Mila Green3e3058a2020-08-27 16:59:2773base::FilePath GetTestAppExecutablePath() {
74 base::FilePath test_executable;
75 if (!base::PathService::Get(base::FILE_EXE, &test_executable))
76 return base::FilePath();
77 return test_executable.DirName()
Mila Greena3991ae2020-10-16 00:10:5578 .Append(FILE_PATH_LITERAL(TEST_APP_FULLNAME_STRING ".app"))
Mila Green3e3058a2020-08-27 16:59:2779 .Append(FILE_PATH_LITERAL("Contents"))
80 .Append(FILE_PATH_LITERAL("MacOS"))
81 .Append(FILE_PATH_LITERAL(TEST_APP_FULLNAME_STRING));
82}
83
Anton Bikineev46bbb972021-05-15 17:53:5384absl::optional<base::FilePath> GetProductPath(UpdaterScope scope) {
85 absl::optional<base::FilePath> path = GetLibraryFolderPath(scope);
Mila Greenf6d82f82021-03-05 22:14:2986 if (!path)
Anton Bikineev46bbb972021-05-15 17:53:5387 return absl::nullopt;
Mila Greenf6d82f82021-03-05 22:14:2988
89 return path->AppendASCII(COMPANY_SHORTNAME_STRING)
Joshua Pawlicki8f755d382020-03-20 19:51:1090 .AppendASCII(PRODUCT_FULLNAME_STRING);
91}
92
Anton Bikineev46bbb972021-05-15 17:53:5393absl::optional<base::FilePath> GetActiveFile(UpdaterScope scope,
Mila Greenf6d82f82021-03-05 22:14:2994 const std::string& id) {
Anton Bikineev46bbb972021-05-15 17:53:5395 const absl::optional<base::FilePath> path =
Mila Green708bf0d92021-03-23 17:33:1596 GetLibraryFolderPath(UpdaterScope::kUser);
Mila Greenf6d82f82021-03-05 22:14:2997 if (!path)
Anton Bikineev46bbb972021-05-15 17:53:5398 return absl::nullopt;
Mila Greenf6d82f82021-03-05 22:14:2999
100 return path->AppendASCII(COMPANY_SHORTNAME_STRING)
Joshua Pawlicki6867d7c2021-01-06 15:51:09101 .AppendASCII(COMPANY_SHORTNAME_STRING "SoftwareUpdate")
102 .AppendASCII("Actives")
103 .AppendASCII(id);
104}
105
Mila Greenf6d82f82021-03-05 22:14:29106void ExpectServiceAbsent(UpdaterScope scope, const std::string& service) {
107 VLOG(0) << __func__ << " - scope: " << scope << ". service: " << service;
Joshua Pawlickicd6925c92020-12-15 15:07:50108 bool success = false;
109 base::RunLoop loop;
Mila Greenf6d82f82021-03-05 22:14:29110 PollLaunchctlList(scope, service, LaunchctlPresence::kAbsent,
Joshua Pawlickicd6925c92020-12-15 15:07:50111 base::TimeDelta::FromSeconds(7),
112 base::BindLambdaForTesting([&](bool result) {
113 success = result;
114 loop.QuitClosure().Run();
115 }));
116 loop.Run();
117 EXPECT_TRUE(success) << service << " is unexpectedly present.";
118}
119
Joshua Pawlicki83d1d8232020-10-23 20:13:31120} // namespace
121
Joshua Pawlicki6867d7c2021-01-06 15:51:09122void EnterTestMode(const GURL& url) {
Adam Norberg14b66a12021-01-20 21:54:03123 ASSERT_TRUE(ExternalConstantsBuilder()
124 .SetUpdateURL(std::vector<std::string>{url.spec()})
125 .SetUseCUP(false)
Mila Green1cb26962021-01-21 01:00:00126 .SetInitialDelay(0.1)
Mila Green59389f12021-02-03 20:52:32127 .SetServerKeepAliveSeconds(1)
Adam Norberg14b66a12021-01-20 21:54:03128 .Overwrite());
Joshua Pawlicki6867d7c2021-01-06 15:51:09129}
130
Anton Bikineev46bbb972021-05-15 17:53:53131absl::optional<base::FilePath> GetDataDirPath(UpdaterScope scope) {
132 absl::optional<base::FilePath> app_path =
Mila Greenf6d82f82021-03-05 22:14:29133 GetApplicationSupportDirectory(scope);
134 if (!app_path) {
135 VLOG(1) << "Failed to get Application support path.";
Anton Bikineev46bbb972021-05-15 17:53:53136 return absl::nullopt;
Mila Greenf6d82f82021-03-05 22:14:29137 }
Joshua Pawlicki6867d7c2021-01-06 15:51:09138
Mila Greenf6d82f82021-03-05 22:14:29139 return app_path->AppendASCII(COMPANY_SHORTNAME_STRING)
Joshua Pawlicki9d1340fc2020-08-14 20:59:35140 .AppendASCII(PRODUCT_FULLNAME_STRING);
141}
142
Mila Greenf6d82f82021-03-05 22:14:29143void Clean(UpdaterScope scope) {
144 Launchd::Domain launchd_domain = LaunchdDomain(scope);
145 Launchd::Type launchd_type = LaunchdType(scope);
146
Anton Bikineev46bbb972021-05-15 17:53:53147 absl::optional<base::FilePath> path = GetProductPath(scope);
Mila Greenf6d82f82021-03-05 22:14:29148 EXPECT_TRUE(path);
149 if (path)
150 EXPECT_TRUE(base::DeletePathRecursively(*path));
Joshua Pawlicki8f755d382020-03-20 19:51:10151 EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Mila Greenf6d82f82021-03-05 22:14:29152 launchd_domain, launchd_type, updater::CopyWakeLaunchdName()));
Joshua Pawlicki8f755d382020-03-20 19:51:10153 EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Mila Greenf6d82f82021-03-05 22:14:29154 launchd_domain, launchd_type,
Mila Green80845642020-12-10 03:44:51155 updater::CopyUpdateServiceInternalLaunchdName()));
Mila Green7414a0ed2020-07-21 21:30:42156 EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Mila Greenf6d82f82021-03-05 22:14:29157 launchd_domain, launchd_type, updater::CopyUpdateServiceLaunchdName()));
158
159 path = GetDataDirPath(scope);
160 EXPECT_TRUE(path);
161 if (path)
162 EXPECT_TRUE(base::DeletePathRecursively(*path));
Joshua Pawlicki3f645882020-08-21 20:36:17163
164 @autoreleasepool {
Mila Greenf6d82f82021-03-05 22:14:29165 RemoveJobFromLaunchd(scope, launchd_domain, launchd_type,
Mila Green3c9375d2021-03-17 16:33:59166 CopyWakeLaunchdName());
167 RemoveJobFromLaunchd(scope, launchd_domain, launchd_type,
Joshua Pawlickicd6925c92020-12-15 15:07:50168 CopyUpdateServiceLaunchdName());
Mila Greenf6d82f82021-03-05 22:14:29169 RemoveJobFromLaunchd(scope, launchd_domain, launchd_type,
Joshua Pawlickicd6925c92020-12-15 15:07:50170 CopyUpdateServiceInternalLaunchdName());
Joshua Pawlicki3f645882020-08-21 20:36:17171 }
Joshua Pawlickibae1c6d2352020-03-19 19:21:44172}
173
Mila Greenf6d82f82021-03-05 22:14:29174void ExpectClean(UpdaterScope scope) {
175 Launchd::Domain launchd_domain = LaunchdDomain(scope);
176 Launchd::Type launchd_type = LaunchdType(scope);
177
Joshua Pawlickibae1c6d2352020-03-19 19:21:44178 // Files must not exist on the file system.
Anton Bikineev46bbb972021-05-15 17:53:53179 absl::optional<base::FilePath> path = GetProductPath(scope);
Mila Greenf6d82f82021-03-05 22:14:29180 EXPECT_TRUE(path);
181 if (path)
182 EXPECT_FALSE(base::PathExists(*path));
Joshua Pawlicki8f755d382020-03-20 19:51:10183 EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29184 launchd_domain, launchd_type, updater::CopyWakeLaunchdName()));
Mila Green8ddc4e02020-05-01 00:15:02185 EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29186 launchd_domain, launchd_type,
Mila Green80845642020-12-10 03:44:51187 updater::CopyUpdateServiceInternalLaunchdName()));
Mila Green7414a0ed2020-07-21 21:30:42188 EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29189 launchd_domain, launchd_type, updater::CopyUpdateServiceLaunchdName()));
190
191 path = GetDataDirPath(scope);
192 EXPECT_TRUE(path);
193 if (path)
194 EXPECT_FALSE(base::PathExists(*path));
195
Joshua Pawlicki6c67e23c2021-05-07 19:32:31196 ExpectServiceAbsent(scope, GetUpdateServiceLaunchdName());
197 ExpectServiceAbsent(scope, GetUpdateServiceInternalLaunchdName());
Joshua Pawlickibae1c6d2352020-03-19 19:21:44198}
199
Mila Greenf6d82f82021-03-05 22:14:29200void ExpectInstalled(UpdaterScope scope) {
201 Launchd::Domain launchd_domain = LaunchdDomain(scope);
202 Launchd::Type launchd_type = LaunchdType(scope);
203
Joshua Pawlickibae1c6d2352020-03-19 19:21:44204 // Files must exist on the file system.
Anton Bikineev46bbb972021-05-15 17:53:53205 absl::optional<base::FilePath> path = GetProductPath(scope);
Mila Greenf6d82f82021-03-05 22:14:29206 EXPECT_TRUE(path);
207 if (path)
208 EXPECT_TRUE(base::PathExists(*path));
209
210 EXPECT_TRUE(Launchd::GetInstance()->PlistExists(launchd_domain, launchd_type,
Mila Green7414a0ed2020-07-21 21:30:42211 CopyWakeLaunchdName()));
Mila Green80845642020-12-10 03:44:51212 EXPECT_TRUE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29213 launchd_domain, launchd_type, CopyUpdateServiceInternalLaunchdName()));
Joshua Pawlickibae1c6d2352020-03-19 19:21:44214}
215
Mila Greenf6d82f82021-03-05 22:14:29216void Install(UpdaterScope scope) {
Mila Green8ddc4e02020-05-01 00:15:02217 const base::FilePath path = GetExecutablePath();
Joshua Pawlickibae1c6d2352020-03-19 19:21:44218 ASSERT_FALSE(path.empty());
Michael Change4785a822020-03-26 20:55:01219 base::CommandLine command_line(path);
Joshua Pawlicki91ce318b2020-09-15 14:35:38220 command_line.AppendSwitch(kInstallSwitch);
Mila Green8ddc4e02020-05-01 00:15:02221 int exit_code = -1;
Mila Greenf6d82f82021-03-05 22:14:29222 ASSERT_TRUE(Run(scope, command_line, &exit_code));
223 EXPECT_EQ(exit_code, 0);
Mila Green8ddc4e02020-05-01 00:15:02224}
225
Mila Greenf6d82f82021-03-05 22:14:29226void ExpectActiveUpdater(UpdaterScope scope) {
227 Launchd::Domain launchd_domain = LaunchdDomain(scope);
228 Launchd::Type launchd_type = LaunchdType(scope);
229
Mila Green8ddc4e02020-05-01 00:15:02230 // Files must exist on the file system.
Anton Bikineev46bbb972021-05-15 17:53:53231 absl::optional<base::FilePath> path = GetProductPath(scope);
Mila Greenf6d82f82021-03-05 22:14:29232 EXPECT_TRUE(path);
233 if (path)
234 EXPECT_TRUE(base::PathExists(*path));
235
Mila Green80845642020-12-10 03:44:51236 EXPECT_TRUE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29237 launchd_domain, launchd_type, CopyUpdateServiceLaunchdName()));
Mila Green8ddc4e02020-05-01 00:15:02238}
239
Mila Greenf6d82f82021-03-05 22:14:29240void RegisterTestApp(UpdaterScope scope) {
Mila Green3e3058a2020-08-27 16:59:27241 const base::FilePath path = GetTestAppExecutablePath();
242 ASSERT_FALSE(path.empty());
243 base::CommandLine command_line(path);
244 command_line.AppendSwitch(kRegisterUpdaterSwitch);
245 int exit_code = -1;
Mila Greenf6d82f82021-03-05 22:14:29246 ASSERT_TRUE(Run(scope, command_line, &exit_code));
247 EXPECT_EQ(exit_code, 0);
Mila Green3e3058a2020-08-27 16:59:27248}
249
Anton Bikineev46bbb972021-05-15 17:53:53250absl::optional<base::FilePath> GetInstalledExecutablePath(UpdaterScope scope) {
Mila Greenf6d82f82021-03-05 22:14:29251 return GetUpdaterExecutablePath(scope);
Mila Greena3991ae2020-10-16 00:10:55252}
253
Mila Greenf6d82f82021-03-05 22:14:29254void ExpectCandidateUninstalled(UpdaterScope scope) {
255 Launchd::Domain launchd_domain = LaunchdDomain(scope);
256 Launchd::Type launchd_type = LaunchdType(scope);
257
Anton Bikineev46bbb972021-05-15 17:53:53258 absl::optional<base::FilePath> versioned_folder_path =
Mila Greenf6d82f82021-03-05 22:14:29259 GetVersionedUpdaterFolderPath(scope);
260 EXPECT_TRUE(versioned_folder_path);
261 if (versioned_folder_path)
262 EXPECT_FALSE(base::PathExists(*versioned_folder_path));
263
264 EXPECT_FALSE(Launchd::GetInstance()->PlistExists(launchd_domain, launchd_type,
265 CopyWakeLaunchdName()));
Mila Greena3991ae2020-10-16 00:10:55266 EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Mila Greenf6d82f82021-03-05 22:14:29267 launchd_domain, launchd_type, CopyUpdateServiceInternalLaunchdName()));
Joshua Pawlicki4abd1322020-08-19 22:05:57268}
269
Mila Greenf6d82f82021-03-05 22:14:29270void Uninstall(UpdaterScope scope) {
Anton Bikineev46bbb972021-05-15 17:53:53271 absl::optional<base::FilePath> path = GetExecutablePath();
Mila Greenf6d82f82021-03-05 22:14:29272 ASSERT_TRUE(path);
273 base::CommandLine command_line(*path);
Mila Green8ddc4e02020-05-01 00:15:02274 command_line.AppendSwitch(kUninstallSwitch);
Joshua Pawlickibae1c6d2352020-03-19 19:21:44275 int exit_code = -1;
Mila Greenf6d82f82021-03-05 22:14:29276 ASSERT_TRUE(Run(scope, command_line, &exit_code));
277 EXPECT_EQ(exit_code, 0);
Joshua Pawlickibae1c6d2352020-03-19 19:21:44278}
279
Anton Bikineev46bbb972021-05-15 17:53:53280absl::optional<base::FilePath> GetFakeUpdaterInstallFolderPath(
Mila Greenf6d82f82021-03-05 22:14:29281 UpdaterScope scope,
282 const base::Version& version) {
283 return GetExecutableFolderPathForVersion(scope, version);
Mila Greena3991ae2020-10-16 00:10:55284}
285
Mila Greenf6d82f82021-03-05 22:14:29286void SetActive(UpdaterScope scope, const std::string& app_id) {
Anton Bikineev46bbb972021-05-15 17:53:53287 const absl::optional<base::FilePath> path = GetActiveFile(scope, app_id);
Mila Green708bf0d92021-03-23 17:33:15288 ASSERT_TRUE(path);
289 VLOG(0) << "Actives file: " << *path;
Joshua Pawlicki6867d7c2021-01-06 15:51:09290 base::File::Error err = base::File::FILE_OK;
Mila Green708bf0d92021-03-23 17:33:15291 EXPECT_TRUE(base::CreateDirectoryAndGetError(path->DirName(), &err))
Joshua Pawlicki6867d7c2021-01-06 15:51:09292 << "Error: " << err;
Mila Green708bf0d92021-03-23 17:33:15293 EXPECT_TRUE(base::WriteFile(*path, ""));
Joshua Pawlicki6867d7c2021-01-06 15:51:09294}
295
Mila Greenf6d82f82021-03-05 22:14:29296void ExpectActive(UpdaterScope scope, const std::string& app_id) {
Anton Bikineev46bbb972021-05-15 17:53:53297 const absl::optional<base::FilePath> path = GetActiveFile(scope, app_id);
Mila Greenf6d82f82021-03-05 22:14:29298 ASSERT_TRUE(path);
299 EXPECT_TRUE(base::PathExists(*path));
300 EXPECT_TRUE(base::PathIsWritable(*path));
Joshua Pawlicki6867d7c2021-01-06 15:51:09301}
302
Mila Greenf6d82f82021-03-05 22:14:29303void ExpectNotActive(UpdaterScope scope, const std::string& app_id) {
Anton Bikineev46bbb972021-05-15 17:53:53304 const absl::optional<base::FilePath> path = GetActiveFile(scope, app_id);
Mila Greenf6d82f82021-03-05 22:14:29305 ASSERT_TRUE(path);
306 EXPECT_FALSE(base::PathExists(*path));
307 EXPECT_FALSE(base::PathIsWritable(*path));
Joshua Pawlicki6867d7c2021-01-06 15:51:09308}
309
Joshua Pawlickia6f88e22021-05-06 14:50:12310void WaitForServerExit(UpdaterScope scope) {
311 base::TimeTicks deadline =
312 base::TimeTicks::Now() + TestTimeouts::action_max_timeout();
313 while (base::TimeTicks::Now() < deadline) {
314 std::string ps_stdout;
315 ASSERT_TRUE(base::GetAppOutput({"ps", "ax", "-o", "command"}, &ps_stdout));
316 if (ps_stdout.find(GetExecutablePath().BaseName().AsUTF8Unsafe()) ==
317 std::string::npos) {
318 return;
319 }
320 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
321 }
322 FAIL() << __func__ << " timed out.";
323}
324
Joshua Pawlickibae1c6d2352020-03-19 19:21:44325} // namespace test
Joshua Pawlickibae1c6d2352020-03-19 19:21:44326} // namespace updater