blob: 8af5308e814f55fd1becc80c1d145028682cf7dd [file] [log] [blame]
// 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 "chrome/updater/test/unit_test_util.h"
#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/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "chrome/updater/test/integration_tests_impl.h"
#include "chrome/updater/test/test_scope.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/re2/src/re2/re2.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/strings/string_number_conversions_win.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/test/test_executables.h"
#include "chrome/updater/win/test/test_strings.h"
#endif
namespace updater::test {
namespace {
std::string ToString(const std::string& s) {
return s;
}
std::string ToString(const std::wstring& s) {
return base::WideToUTF8(s);
}
} // namespace
TEST(UnitTestUtil, ToString) {
EXPECT_EQ(ToString("test"), ToString(L"test"));
}
TEST(UnitTestUtil, Processes) {
auto print_processes_tester =
[](const base::FilePath::StringType& process_name) {
const std::string print_processes = PrintProcesses(process_name);
const std::string regex_string = base::StringPrintf(
R"(Found processes:\n)"
R"(={72}\n(%s, pid=\d*, creation time=.*\n){2}={72}\n$)",
ToString(process_name).c_str());
bool is_match =
re2::RE2::FullMatch(print_processes, re2::RE2(regex_string));
if (!is_match) {
ADD_FAILURE() << "regex:'" << regex_string << "'" << std::endl
<< print_processes;
}
return is_match;
};
#if BUILDFLAG(IS_WIN)
// Ensure the test process is not running before the test.
EXPECT_TRUE(KillProcesses(kTestProcessExecutableName, 0));
EXPECT_TRUE(WaitForProcessesToExit(kTestProcessExecutableName,
TestTimeouts::action_timeout()));
EXPECT_FALSE(IsProcessRunning(kTestProcessExecutableName));
// Start two long-lived processes and expect to find them running.
std::vector<base::Process> long_running;
long_running.push_back(
LongRunningProcess(GetUpdaterScopeForTesting(), GetTestName(), nullptr));
long_running.push_back(
LongRunningProcess(GetUpdaterScopeForTesting(), GetTestName(), nullptr));
for (const base::Process& p : long_running) {
EXPECT_TRUE(p.IsValid());
}
EXPECT_TRUE(IsProcessRunning(kTestProcessExecutableName));
EXPECT_TRUE(print_processes_tester(kTestProcessExecutableName));
// Terminate the long-lived processes, expect to find them not running, then
// inspect their exit code.
static constexpr int kExitCode = 12345;
EXPECT_FALSE(WaitForProcessesToExit(kTestProcessExecutableName,
base::Milliseconds(1)));
EXPECT_TRUE(KillProcesses(kTestProcessExecutableName, kExitCode));
EXPECT_TRUE(WaitForProcessesToExit(kTestProcessExecutableName,
TestTimeouts::action_timeout()));
EXPECT_FALSE(IsProcessRunning(kTestProcessExecutableName));
for (const base::Process& p : long_running) {
int exit_code = 0;
EXPECT_TRUE(
p.WaitForExitWithTimeout(TestTimeouts::tiny_timeout(), &exit_code));
EXPECT_EQ(exit_code, kExitCode);
}
#else
// Test the state of the process for the unit test process itself.
base::FilePath::StringType unit_test = [] {
base::FilePath unit_test_executable;
base::PathService::Get(base::FILE_EXE, &unit_test_executable);
return unit_test_executable.BaseName().value();
}();
EXPECT_TRUE(IsProcessRunning(unit_test));
EXPECT_FALSE(WaitForProcessesToExit(unit_test, base::Milliseconds(1)));
EXPECT_TRUE(print_processes_tester(unit_test));
#endif // IS_WIN
}
TEST(UnitTestUtil, GetTestName) {
EXPECT_EQ(GetTestName(), "UnitTestUtil.GetTestName");
}
// Enable the test to print the effective values for the test timeouts when
// debugging timeout issues.
TEST(UnitTestUtil, DISABLED_PrintTestTimeouts) {
VLOG(0) << "action-timeout:"
<< TestTimeouts::action_timeout().InMilliseconds()
<< ", action-max-timeout:"
<< TestTimeouts::action_max_timeout().InMilliseconds()
<< ", test-launcher-timeout:"
<< TestTimeouts::test_launcher_timeout().InMilliseconds();
}
TEST(UnitTestUtil, DeleteFileAndEmptyParentDirectories) {
EXPECT_FALSE(DeleteFileAndEmptyParentDirectories(std::nullopt));
const base::FilePath path_not_found(FILE_PATH_LITERAL("path-not-found"));
EXPECT_TRUE(DeleteFileAndEmptyParentDirectories(path_not_found));
// Create something in temp so that `DeleteFileAndEmptyParentDirectories()`
// does not delete the temp directory of this process because it is empty.
base::ScopedTempDir a_temp_dir;
ASSERT_TRUE(a_temp_dir.CreateUniqueTempDir());
base::FilePath temp_path;
ASSERT_TRUE(GetTempDir(&temp_path));
// Create and delete the following path "some_dir/dir_in_dir/file_in_dir".
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath dir_in_dir;
EXPECT_TRUE(base::CreateTemporaryDirInDir(
temp_dir.GetPath(), FILE_PATH_LITERAL("UnitTestUtil"), &dir_in_dir));
base::FilePath file_in_dir;
EXPECT_TRUE(CreateTemporaryFileInDir(dir_in_dir, &file_in_dir));
EXPECT_TRUE(DeleteFileAndEmptyParentDirectories(file_in_dir));
EXPECT_FALSE(base::DirectoryExists(temp_dir.GetPath()));
EXPECT_TRUE(base::DirectoryExists(temp_path));
}
#if BUILDFLAG(IS_WIN)
TEST(UnitTestUtil, FindProcesses) {
base::CommandLine command_line = GetTestProcessCommandLine(
GetUpdaterScopeForTesting(), test::GetTestName());
// Create a unique name for a shared event to be waited for in the test
// process and signaled in this test.
EventHolder event_holder(CreateWaitableEventForTest());
command_line.AppendSwitchNative(kTestEventToWaitOn, event_holder.name);
const base::Process process = base::LaunchProcess(command_line, {});
ASSERT_TRUE(process.IsValid());
EXPECT_TRUE(test::WaitFor([&] { return process.IsRunning(); }));
EXPECT_EQ(test::FindProcesses(kTestProcessExecutableName).size(), 1U);
event_holder.event.Signal();
EXPECT_TRUE(test::WaitFor([&] { return !process.IsRunning(); }));
EXPECT_TRUE(test::FindProcesses(kTestProcessExecutableName).empty());
}
#endif // BUILDFLAG(IS_WIN)
} // namespace updater::test