blob: 87c52f6cdd22c721f72ee0e331bb9a3145891651 [file] [log] [blame]
// 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 <stdint.h>
#include <string>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/test/bind.h"
#include "base/version.h"
#include "chrome/common/mac/launchd.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/launchd_util.h"
#import "chrome/updater/mac/util.h"
#include "chrome/updater/mac/xpc_service_names.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/test/integration_tests.h"
#include "chrome/updater/test/test_app/constants.h"
#include "chrome/updater/test/test_app/test_app_version.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace updater {
namespace test {
// crbug.com/1112527: These tests are not compatible with component build.
#if !defined(COMPONENT_BUILD)
namespace {
void RemoveJobFromLaunchd(Launchd::Domain domain,
Launchd::Type type,
base::ScopedCFTypeRef<CFStringRef> name) {
EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(domain, type, name))
<< "Failed to delete plist for " << name;
// Return value is ignored, since RemoveJob returns false if the job already
// doesn't exist.
Launchd::GetInstance()->RemoveJob(base::SysCFStringRefToUTF8(name));
}
base::FilePath GetExecutablePath() {
base::FilePath test_executable;
if (!base::PathService::Get(base::FILE_EXE, &test_executable))
return base::FilePath();
return test_executable.DirName()
.Append(FILE_PATH_LITERAL(PRODUCT_FULLNAME_STRING ".app"))
.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("MacOS"))
.Append(FILE_PATH_LITERAL(PRODUCT_FULLNAME_STRING));
}
base::FilePath GetTestAppExecutablePath() {
base::FilePath test_executable;
if (!base::PathService::Get(base::FILE_EXE, &test_executable))
return base::FilePath();
return test_executable.DirName()
.Append(FILE_PATH_LITERAL(TEST_APP_FULLNAME_STRING ".app"))
.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("MacOS"))
.Append(FILE_PATH_LITERAL(TEST_APP_FULLNAME_STRING));
}
base::FilePath GetProductPath() {
return base::mac::GetUserLibraryPath()
.AppendASCII(COMPANY_SHORTNAME_STRING)
.AppendASCII(PRODUCT_FULLNAME_STRING);
}
base::FilePath GetActiveFile(const std::string& id) {
return base::GetHomeDir()
.AppendASCII("Library")
.AppendASCII(COMPANY_SHORTNAME_STRING)
.AppendASCII(COMPANY_SHORTNAME_STRING "SoftwareUpdate")
.AppendASCII("Actives")
.AppendASCII(id);
}
void ExpectServiceAbsent(const std::string& service) {
bool success = false;
base::RunLoop loop;
PollLaunchctlList(service, LaunchctlPresence::kAbsent,
base::TimeDelta::FromSeconds(7),
base::BindLambdaForTesting([&](bool result) {
success = result;
loop.QuitClosure().Run();
}));
loop.Run();
EXPECT_TRUE(success) << service << " is unexpectedly present.";
}
} // namespace
#endif // defined(COMPONENT_BUILD
void EnterTestMode(const GURL& url) {
@autoreleasepool {
NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
initWithSuiteName:[NSString
stringWithUTF8String:kUserDefaultsSuiteName]];
[userDefaults
setURL:[NSURL URLWithString:base::SysUTF8ToNSString(url.spec())]
forKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
[userDefaults
setBool:NO
forKey:[NSString stringWithUTF8String:kDevOverrideKeyUseCUP]];
}
}
// crbug.com/1112527: These tests are not compatible with component build.
#if !defined(COMPONENT_BUILD)
base::FilePath GetDataDirPath() {
return base::mac::GetUserLibraryPath()
.AppendASCII("Application Support")
.AppendASCII(COMPANY_SHORTNAME_STRING)
.AppendASCII(PRODUCT_FULLNAME_STRING);
}
void Clean() {
EXPECT_TRUE(base::DeletePathRecursively(GetProductPath()));
EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Launchd::User, Launchd::Agent, updater::CopyWakeLaunchdName()));
EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Launchd::User, Launchd::Agent,
updater::CopyUpdateServiceInternalLaunchdName()));
EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
Launchd::User, Launchd::Agent, updater::CopyUpdateServiceLaunchdName()));
EXPECT_TRUE(base::DeletePathRecursively(GetDataDirPath()));
@autoreleasepool {
NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
initWithSuiteName:[NSString
stringWithUTF8String:kUserDefaultsSuiteName]];
[userDefaults
removeObjectForKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
[userDefaults
removeObjectForKey:[NSString
stringWithUTF8String:kDevOverrideKeyUseCUP]];
// TODO(crbug.com/1096654): support machine case (Launchd::Domain::Local and
// Launchd::Type::Daemon).
RemoveJobFromLaunchd(Launchd::Domain::User, Launchd::Type::Agent,
CopyUpdateServiceLaunchdName());
RemoveJobFromLaunchd(Launchd::Domain::User, Launchd::Type::Agent,
CopyUpdateServiceInternalLaunchdName());
}
}
void ExpectClean() {
// Files must not exist on the file system.
EXPECT_FALSE(base::PathExists(GetProductPath()));
EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, updater::CopyWakeLaunchdName()));
EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent,
updater::CopyUpdateServiceInternalLaunchdName()));
EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, updater::CopyUpdateServiceLaunchdName()));
EXPECT_FALSE(base::PathExists(GetDataDirPath()));
ExpectServiceAbsent(kUpdateServiceLaunchdName);
ExpectServiceAbsent(kUpdateServiceInternalLaunchdName);
}
void ExpectInstalled() {
// Files must exist on the file system.
EXPECT_TRUE(base::PathExists(GetProductPath()));
EXPECT_TRUE(Launchd::GetInstance()->PlistExists(Launchd::User, Launchd::Agent,
CopyWakeLaunchdName()));
EXPECT_TRUE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, CopyUpdateServiceInternalLaunchdName()));
}
void Install() {
const base::FilePath path = GetExecutablePath();
ASSERT_FALSE(path.empty());
base::CommandLine command_line(path);
command_line.AppendSwitch(kInstallSwitch);
int exit_code = -1;
ASSERT_TRUE(Run(command_line, &exit_code));
EXPECT_EQ(0, exit_code);
}
void ExpectActive() {
// Files must exist on the file system.
EXPECT_TRUE(base::PathExists(GetProductPath()));
EXPECT_TRUE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, CopyUpdateServiceLaunchdName()));
}
void RegisterTestApp() {
const base::FilePath path = GetTestAppExecutablePath();
ASSERT_FALSE(path.empty());
base::CommandLine command_line(path);
command_line.AppendSwitch(kRegisterUpdaterSwitch);
int exit_code = -1;
ASSERT_TRUE(Run(command_line, &exit_code));
EXPECT_EQ(0, exit_code);
}
base::FilePath GetInstalledExecutablePath() {
return GetUpdaterExecutablePath();
}
void ExpectCandidateUninstalled() {
base::FilePath versioned_folder_path = GetVersionedUpdaterFolderPath();
EXPECT_FALSE(base::PathExists(versioned_folder_path));
EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, CopyWakeLaunchdName()));
EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
Launchd::User, Launchd::Agent, CopyUpdateServiceInternalLaunchdName()));
}
void Uninstall() {
if (::testing::Test::HasFailure())
PrintLog();
// Copy logs from GetDataDirPath() before updater uninstalls itself
// and deletes the path.
CopyLog(GetDataDirPath());
// Uninstall the updater.
const base::FilePath path = GetExecutablePath();
ASSERT_FALSE(path.empty());
base::CommandLine command_line(path);
command_line.AppendSwitch(kUninstallSwitch);
int exit_code = -1;
ASSERT_TRUE(Run(command_line, &exit_code));
EXPECT_EQ(0, exit_code);
}
base::FilePath GetFakeUpdaterInstallFolderPath(const base::Version& version) {
return GetExecutableFolderPathForVersion(version);
}
void SetActive(const std::string& app_id) {
base::File::Error err = base::File::FILE_OK;
base::FilePath actives_file = GetActiveFile(app_id);
EXPECT_TRUE(base::CreateDirectoryAndGetError(actives_file.DirName(), &err))
<< "Error: " << err;
EXPECT_TRUE(base::WriteFile(actives_file, ""));
}
void ExpectActive(const std::string& app_id) {
base::FilePath path = GetActiveFile(app_id);
EXPECT_TRUE(base::PathExists(path) && base::PathIsWritable(path))
<< app_id << " is not active";
}
void ExpectNotActive(const std::string& app_id) {
base::FilePath path = GetActiveFile(app_id);
EXPECT_FALSE(base::PathExists(path) && base::PathIsWritable(path))
<< app_id << " is active.";
}
#endif // !defined(COMPONENT_BUILD)
} // namespace test
} // namespace updater