test: Rework TestPaths interface for obtaining 32-bit build artifacts

The design for running all Crashpad unit tests on Chromium’s try- and
buildbots involves pulling all tests into a single monolithic
crashpad_tests executable. Many Crashpad tests base the name of their
child executables or modules on the name of the main test executable.
Since the main test executable will have a different name in the
in-Chromium build, knowledge of the test executable name (referred to as
“module” here) needs to be added to the tests themselves.

This introduces TestPaths::BuildArtifact(), which allows the module name
to be specified. For Crashpad’s standalone build, the module name is
verified against the main test executable’s name.
TestPaths::BuildArtifact() can also locate paths in the alternate 32-bit
output directory for 64-bit Windows tests, taking on the responsibility
for what the new (5e9ed4cb9f69) TestPaths::Output32BitDirectory(), now
obsolete, did.

Bug: chromium:779790
Change-Id: I64c4a2190b6319e487c999812a7cfc512a75a700
Reviewed-on: https://chromium-review.googlesource.com/747536
Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Mark Mentovai 2017-11-01 10:37:01 -04:00
parent af594c8deb
commit 1669ca2bac
19 changed files with 246 additions and 152 deletions

View File

@ -37,8 +37,8 @@ namespace {
constexpr DWORD kExpectedExitCode = 0x1CEB00DA;
void StartAndCrashWithExtendedHandler(const base::FilePath& temp_dir) {
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_handler_test_extended_handler.exe"));
base::FilePath handler_path = TestPaths::BuildArtifact(
L"handler", L"extended_handler", TestPaths::FileType::kExecutable);
CrashpadClient client;
ASSERT_TRUE(client.StartHandler(handler_path,

View File

@ -90,8 +90,8 @@ int CrashOtherProgram(int argc, wchar_t* argv[]) {
// Launch another process that hangs.
base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable =
test_executable.DirName().Append(L"hanging_program.exe").value();
base::FilePath child_test_executable =
test_executable.DirName().Append(L"hanging_program.exe");
ChildLauncher child(child_test_executable, argv[1]);
child.Start();
if (testing::Test::HasFatalFailure()) {

View File

@ -141,13 +141,10 @@ TEST(CrashpadInfoClientOptions, OneModule) {
TEST(CrashpadInfoClientOptions, TwoModules) {
// Open the module, which has its own CrashpadInfo structure.
#if defined(OS_MACOSX)
const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".so");
#elif defined(OS_WIN)
const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".dll");
#endif
base::FilePath module_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension);
base::FilePath module_path =
TestPaths::BuildArtifact(FILE_PATH_LITERAL("snapshot"),
FILE_PATH_LITERAL("module"),
TestPaths::FileType::kLoadableModule);
#if defined(OS_MACOSX)
ScopedModuleHandle module(
dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL));

View File

@ -51,13 +51,16 @@ namespace test {
namespace {
// \return The path to crashpad_snapshot_test_module_crashy_initializer.so
std::string ModuleWithCrashyInitializer() {
return TestPaths::Executable().value() + "_module_crashy_initializer.so";
base::FilePath ModuleWithCrashyInitializer() {
return TestPaths::BuildArtifact("snapshot",
"module_crashy_initializer",
TestPaths::FileType::kLoadableModule);
}
//! \return The path to the crashpad_snapshot_test_no_op executable.
base::FilePath NoOpExecutable() {
return base::FilePath(TestPaths::Executable().value() + "_no_op");
return TestPaths::BuildArtifact(
"snapshot", "no_op", TestPaths::FileType::kExecutable);
}
class TestMachOImageAnnotationsReader final
@ -183,7 +186,7 @@ class TestMachOImageAnnotationsReader final
case kCrashModuleInitialization:
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization().
expected_annotation = ModuleWithCrashyInitializer();
expected_annotation = ModuleWithCrashyInitializer().value();
break;
case kCrashDyld:
@ -402,7 +405,7 @@ class TestMachOImageAnnotationsReader final
case kCrashModuleInitialization: {
// Load a module that crashes while executing a module initializer.
void* dl_handle = dlopen(ModuleWithCrashyInitializer().c_str(),
void* dl_handle = dlopen(ModuleWithCrashyInitializer().value().c_str(),
RTLD_LAZY | RTLD_LOCAL);
// This should have crashed in the dlopen(). If dlopen() failed, the

View File

@ -121,7 +121,7 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate {
DISALLOW_COPY_AND_ASSIGN(CrashingDelegate);
};
void TestCrashingChild(const base::FilePath& directory) {
void TestCrashingChild(TestPaths::Architecture architecture) {
// Set up the registration server on a background thread.
ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent");
@ -141,13 +141,11 @@ void TestCrashingChild(const base::FilePath& directory) {
<< ErrorMessage("WaitForSingleObject");
// Spawn a child process, passing it the pipe name to connect to.
std::wstring child_test_executable = directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_crashing_child.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"snapshot",
L"crashing_child",
TestPaths::FileType::kExecutable,
architecture);
ChildLauncher child(child_test_executable, pipe_name);
ASSERT_NO_FATAL_FAILURE(child.Start());
@ -166,17 +164,16 @@ void TestCrashingChild(const base::FilePath& directory) {
}
TEST(ExceptionSnapshotWinTest, ChildCrash) {
TestCrashingChild(TestPaths::Executable().DirName());
TestCrashingChild(TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestCrashingChild(output_32_bit_directory);
TestCrashingChild(TestPaths::Architecture::k32Bit);
}
#endif // ARCH_CPU_64_BITS
@ -229,7 +226,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate {
DISALLOW_COPY_AND_ASSIGN(SimulateDelegate);
};
void TestDumpWithoutCrashingChild(const base::FilePath& directory) {
void TestDumpWithoutCrashingChild(TestPaths::Architecture architecture) {
// Set up the registration server on a background thread.
ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent");
@ -249,14 +246,11 @@ void TestDumpWithoutCrashingChild(const base::FilePath& directory) {
<< ErrorMessage("WaitForSingleObject");
// Spawn a child process, passing it the pipe name to connect to.
std::wstring child_test_executable =
directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_dump_without_crashing.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"snapshot",
L"dump_without_crashing",
TestPaths::FileType::kExecutable,
architecture);
ChildLauncher child(child_test_executable, pipe_name);
ASSERT_NO_FATAL_FAILURE(child.Start());
@ -275,17 +269,16 @@ void TestDumpWithoutCrashingChild(const base::FilePath& directory) {
}
TEST(SimulateCrash, ChildDumpWithoutCrashing) {
TestDumpWithoutCrashingChild(TestPaths::Executable().DirName());
TestDumpWithoutCrashingChild(TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestDumpWithoutCrashingChild(output_32_bit_directory);
TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit);
}
#endif // ARCH_CPU_64_BITS

View File

@ -43,15 +43,14 @@ enum TestType {
kCrashDebugBreak,
};
void TestExtraMemoryRanges(TestType type, const base::FilePath& directory) {
void TestExtraMemoryRanges(TestType type,
TestPaths::Architecture architecture) {
// Spawn a child process, passing it the pipe name to connect to.
std::wstring child_test_executable = directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_extra_memory_ranges.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"snapshot",
L"extra_memory_ranges",
TestPaths::FileType::kExecutable,
architecture);
ChildLauncher child(child_test_executable, L"");
ASSERT_NO_FATAL_FAILURE(child.Start());
@ -101,30 +100,28 @@ void TestExtraMemoryRanges(TestType type, const base::FilePath& directory) {
}
TEST(ExtraMemoryRanges, DontCrash) {
TestExtraMemoryRanges(kDontCrash, TestPaths::Executable().DirName());
TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::kDefault);
}
TEST(ExtraMemoryRanges, CrashDebugBreak) {
TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Executable().DirName());
TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(ExtraMemoryRanges, DontCrashWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestExtraMemoryRanges(kDontCrash, output_32_bit_directory);
TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit);
}
TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestExtraMemoryRanges(kCrashDebugBreak, output_32_bit_directory);
TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit);
}
#endif // ARCH_CPU_64_BITS

View File

@ -48,15 +48,14 @@ enum TestType {
kCrashDebugBreak,
};
void TestAnnotationsOnCrash(TestType type, const base::FilePath& directory) {
void TestAnnotationsOnCrash(TestType type,
TestPaths::Architecture architecture) {
// Spawn a child process, passing it the pipe name to connect to.
std::wstring child_test_executable = directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_annotations.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"snapshot",
L"annotations",
TestPaths::FileType::kExecutable,
architecture);
ChildLauncher child(child_test_executable, L"");
ASSERT_NO_FATAL_FAILURE(child.Start());
@ -148,30 +147,28 @@ void TestAnnotationsOnCrash(TestType type, const base::FilePath& directory) {
}
TEST(PEImageAnnotationsReader, DontCrash) {
TestAnnotationsOnCrash(kDontCrash, TestPaths::Executable().DirName());
TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::kDefault);
}
TEST(PEImageAnnotationsReader, CrashDebugBreak) {
TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Executable().DirName());
TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(PEImageAnnotationsReader, DontCrashWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestAnnotationsOnCrash(kDontCrash, output_32_bit_directory);
TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit);
}
TEST(PEImageAnnotationsReader, CrashDebugBreakWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestAnnotationsOnCrash(kCrashDebugBreak, output_32_bit_directory);
TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit);
}
#endif // ARCH_CPU_64_BITS

View File

@ -31,20 +31,18 @@ namespace crashpad {
namespace test {
namespace {
void TestImageReaderChild(const base::FilePath& directory) {
void TestImageReaderChild(const TestPaths::Architecture architecture) {
UUID done_uuid;
done_uuid.InitializeWithNew();
ScopedKernelHANDLE done(
CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent");
std::wstring child_test_executable = directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_image_reader.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"snapshot",
L"image_reader",
TestPaths::FileType::kExecutable,
architecture);
ChildLauncher child(child_test_executable, done_uuid.ToString16());
ASSERT_NO_FATAL_FAILURE(child.Start());
@ -113,17 +111,16 @@ void TestImageReaderChild(const base::FilePath& directory) {
}
TEST(ProcessSnapshotTest, CrashpadInfoChild) {
TestImageReaderChild(TestPaths::Executable().DirName());
TestImageReaderChild(TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestImageReaderChild(output_32_bit_directory);
TestImageReaderChild(TestPaths::Architecture::k32Bit);
}
#endif

View File

@ -18,6 +18,7 @@
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "test/multiprocess.h"
@ -48,7 +49,7 @@ class MultiprocessExec : public Multiprocess {
//! process in its `argv[]` vector. This vector must begin at `argv[1]`,
//! as \a command is implicitly used as `argv[0]`. This argument may be
//! `nullptr` if no command-line arguments are to be passed.
void SetChildCommand(const std::string& command,
void SetChildCommand(const base::FilePath& command,
const std::vector<std::string>* arguments);
protected:
@ -61,7 +62,7 @@ class MultiprocessExec : public Multiprocess {
// Multiprocess:
void MultiprocessChild() override;
std::string command_;
base::FilePath command_;
std::vector<std::string> arguments_;
#if defined(OS_POSIX)
std::vector<const char*> argv_;

View File

@ -40,7 +40,8 @@ MultiprocessExec::MultiprocessExec()
}
void MultiprocessExec::SetChildCommand(
const std::string& command, const std::vector<std::string>* arguments) {
const base::FilePath& command,
const std::vector<std::string>* arguments) {
command_ = command;
if (arguments) {
arguments_ = *arguments;
@ -62,7 +63,7 @@ void MultiprocessExec::PreFork() {
// process, building it is a hazardous operation in that process.
ASSERT_TRUE(argv_.empty());
argv_.push_back(command_.c_str());
argv_.push_back(command_.value().c_str());
for (const std::string& argument : arguments_) {
argv_.push_back(argument.c_str());
}

View File

@ -48,17 +48,10 @@ class TestMultiprocessExec final : public MultiprocessExec {
TEST(MultiprocessExec, MultiprocessExec) {
TestMultiprocessExec multiprocess_exec;
base::FilePath test_executable = TestPaths::Executable();
#if defined(OS_POSIX)
std::string child_test_executable = test_executable.value();
#elif defined(OS_WIN)
std::string child_test_executable =
base::UTF16ToUTF8(test_executable.RemoveFinalExtension().value());
#endif // OS_POSIX
child_test_executable += "_multiprocess_exec_test_child";
#if defined(OS_WIN)
child_test_executable += ".exe";
#endif
base::FilePath child_test_executable = TestPaths::BuildArtifact(
FILE_PATH_LITERAL("test"),
FILE_PATH_LITERAL("multiprocess_exec_test_child"),
TestPaths::FileType::kExecutable);
multiprocess_exec.SetChildCommand(child_test_executable, nullptr);
multiprocess_exec.Run();
}

View File

@ -102,7 +102,7 @@ MultiprocessExec::MultiprocessExec()
}
void MultiprocessExec::SetChildCommand(
const std::string& command,
const base::FilePath& command,
const std::vector<std::string>* arguments) {
command_ = command;
if (arguments) {
@ -119,7 +119,7 @@ void MultiprocessExec::PreFork() {
ASSERT_FALSE(command_.empty());
command_line_.clear();
AppendCommandLineArgument(base::UTF8ToUTF16(command_), &command_line_);
AppendCommandLineArgument(command_.value(), &command_line_);
for (size_t i = 0; i < arguments_.size(); ++i) {
AppendCommandLineArgument(base::UTF8ToUTF16(arguments_[i]), &command_line_);
}
@ -154,7 +154,7 @@ void MultiprocessExec::MultiprocessChild() {
startup_info.hStdOutput = info()->pipe_c2p_write.get();
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startup_info.dwFlags = STARTF_USESTDHANDLES;
PCHECK(CreateProcess(base::UTF8ToUTF16(command_).c_str(),
PCHECK(CreateProcess(command_.value().c_str(),
&command_line_[0], // This cannot be constant, per MSDN.
nullptr,
nullptr,

View File

@ -90,6 +90,23 @@ base::FilePath TestDataRootInternal() {
return base::FilePath(base::FilePath::kCurrentDirectory);
}
#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
// Returns the pathname of a directory containing 32-bit test build output.
//
// It would be better for this to be named 32BitOutputDirectory(), but thats
// not a legal name.
base::FilePath Output32BitDirectory() {
const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT");
if (!environment_value) {
return base::FilePath();
}
return base::FilePath(environment_value);
}
#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
} // namespace
// static
@ -106,16 +123,61 @@ base::FilePath TestPaths::TestDataRoot() {
return *test_data_root;
}
// static
base::FilePath TestPaths::BuildArtifact(
const base::FilePath::StringType& module,
const base::FilePath::StringType& artifact,
FileType file_type,
Architecture architecture) {
base::FilePath directory;
switch (architecture) {
case Architecture::kDefault:
directory = Executable().DirName();
break;
#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
case Architecture::k32Bit:
directory = Output32BitDirectory();
CHECK(!directory.empty());
break;
#endif // OS_WIN && ARCH_CPU_64_BITS
}
base::FilePath::StringType test_name =
FILE_PATH_LITERAL("crashpad_") + module + FILE_PATH_LITERAL("_test");
#if !defined(CRASHPAD_IN_CHROMIUM)
CHECK(Executable().BaseName().RemoveFinalExtension().value() == test_name);
#endif // !CRASHPAD_IN_CHROMIUM
base::FilePath::StringType extension;
switch (file_type) {
case FileType::kNone:
break;
case FileType::kExecutable:
#if defined(OS_WIN)
extension = FILE_PATH_LITERAL(".exe");
#endif // OS_WIN
break;
case FileType::kLoadableModule:
#if defined(OS_WIN)
extension = FILE_PATH_LITERAL(".dll");
#else // OS_WIN
extension = FILE_PATH_LITERAL(".so");
#endif // OS_WIN
break;
}
return directory.Append(test_name + FILE_PATH_LITERAL("_") + artifact +
extension);
}
#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
// static
base::FilePath TestPaths::Output32BitDirectory() {
const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT");
if (!environment_value) {
return base::FilePath();
}
return base::FilePath(environment_value);
bool TestPaths::Has32BitBuildArtifacts() {
return !Output32BitDirectory().empty();
}
#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS)

View File

@ -25,6 +25,38 @@ namespace test {
//! \brief Functions to obtain paths from within tests.
class TestPaths {
public:
//! \brief The type of file requested of BuildArtifact().
//!
//! This is used to establish the file extension used by the returned path.
enum class FileType {
//! \brief No file extension is requested.
kNone = 0,
//! \brief `.exe` will be used on Windows, and no file extension will be
//! used on other platforms.
kExecutable,
//! \brief `.dll` will be used on Windows, and `.so` will be used on other
//! platforms.
kLoadableModule,
};
//! \brief The architecture of the file requested of BuildArtifact().
enum class Architecture {
//! \brief The default architecture is requested. This is usually the same
//! architecture as the running process.
kDefault = 0,
#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN
//! \brief The 32-bit variant is requested.
//!
//! On Windows, when running 64-bit code, the 32-bit variant can be
//! requested. Before doing so, Has32BitBuildArtifacts() must be called and
//! must return `true`. Otherwise, execution will be aborted.
k32Bit,
#endif // OS_WIN && ARCH_CPU_64_BITS
};
//! \brief Returns the pathname of the currently-running test executable.
//!
//! On failure, aborts execution.
@ -43,21 +75,50 @@ class TestPaths {
//! files.
static base::FilePath TestDataRoot();
//! \brief Returns the pathname of a build artifact.
//!
//! \param[in] module The name of the Crashpad module associated with the
//! artifact, such as `"util"` or `"snapshot"`. \a module must correspond
//! to the module of the calling code, or execution will be aborted.
//! \param[in] artifact The name of the specific artifact.
//! \param[in] file_type The artifacts type, used to establish the returned
//! paths extension.
//! \param[in] architecture The artifacts architecture.
//!
//! \return The computed pathname to the build artifact.
//!
//! For example, the following snippet will return a path to
//! `crashpad_snapshot_test_module.so` or `crashpad_snapshot_test_module.dll`
//! (depending on platform) in the same directory as the currently running
//! executable:
//!
//! \code
//! base::FilePath path = TestPaths::BuildArtifact(
//! FILE_PATH_LITERAL("snapshot"),
//! FILE_PATH_LITERAL("module"),
//! TestPaths::FileType::kLoadableModule);
//! \endcode
static base::FilePath BuildArtifact(
const base::FilePath::StringType& module,
const base::FilePath::StringType& artifact,
FileType file_type,
Architecture architecture = Architecture::kDefault);
#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN
//! \brief Returns the pathname of a directory containing 32-bit test build
//! output.
//! \return `true` if 32-bit build artifacts are available.
//!
//! Tests that require the use of 32-bit build output should call this
//! function to locate that output. This function is only provided to allow
//! 64-bit test code to locate 32-bit output. 32-bit test code can find 32-bit
//! output in its own directory, the parent of Executable().
//! function to determine whether that output is available. This function is
//! only provided to aid 64-bit test code in locating 32-bit output. Only if
//! this function indicates that 32-bit output is available, 64-bit test code
//! may call BuildArtifact() with Architecture::k32Bit to obtain a path to the
//! 32-bit output.
//!
//! If the `CRASHPAD_TEST_32_BIT_OUTPUT` environment variable is set, its
//! value will be returned. Otherwise, this function will return an empty
//! path, and tests that require the use of 32-bit build output should disable
//! themselves. The DISABLED_TEST() macro may be useful for this purpose.
static base::FilePath Output32BitDirectory();
#endif
//! 32-bit test code may assume the existence of 32-bit build output, which
//! can be found its own directory, and located by calling BuildArtifact()
//! with Architecture::kDefault.
static bool Has32BitBuildArtifacts();
#endif // OS_WIN && ARCH_CPU_64_BITS
DISALLOW_IMPLICIT_CONSTRUCTORS(TestPaths);
};

View File

@ -21,15 +21,14 @@
namespace crashpad {
namespace test {
ChildLauncher::ChildLauncher(const std::wstring& executable,
ChildLauncher::ChildLauncher(const base::FilePath& executable,
const std::wstring& command_line)
: executable_(executable),
command_line_(command_line),
process_handle_(),
main_thread_handle_(),
stdout_read_handle_(),
stdin_write_handle_() {
}
stdin_write_handle_() {}
ChildLauncher::~ChildLauncher() {
if (process_handle_.is_valid())
@ -76,10 +75,10 @@ void ChildLauncher::Start() {
startup_info.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION process_information;
std::wstring command_line;
AppendCommandLineArgument(executable_, &command_line);
AppendCommandLineArgument(executable_.value(), &command_line);
command_line += L" ";
command_line += command_line_;
ASSERT_TRUE(CreateProcess(executable_.c_str(),
ASSERT_TRUE(CreateProcess(executable_.value().c_str(),
&command_line[0],
nullptr,
nullptr,

View File

@ -19,6 +19,7 @@
#include <string>
#include "base/files/file_path.h"
#include "util/win/scoped_handle.h"
namespace crashpad {
@ -32,7 +33,7 @@ class ChildLauncher {
public:
//! \brief Creates the object. \a executable will be escaped and prepended to
//! \a command_line to build the command line of the child.
ChildLauncher(const std::wstring& executable,
ChildLauncher(const base::FilePath& executable,
const std::wstring& command_line);
~ChildLauncher();
@ -62,7 +63,7 @@ class ChildLauncher {
HANDLE stdin_write_handle() const { return stdin_write_handle_.get(); }
private:
std::wstring executable_;
base::FilePath executable_;
std::wstring command_line_;
ScopedKernelHANDLE process_handle_;
ScopedKernelHANDLE main_thread_handle_;

View File

@ -59,7 +59,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
base::FilePath server_path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/http_transport_test_server.py"));
#if defined(OS_POSIX)
SetChildCommand(server_path.value(), nullptr);
SetChildCommand(server_path, nullptr);
#elif defined(OS_WIN)
// Explicitly invoke a shell and python so that python can be found in the
// path, and run the test script.
@ -67,7 +67,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
args.push_back("/c");
args.push_back("python");
args.push_back(base::UTF16ToUTF8(server_path.value()));
SetChildCommand(getenv("COMSPEC"), &args);
SetChildCommand(base::FilePath(_wgetenv(L"COMSPEC")), &args);
#endif // OS_POSIX
}

View File

@ -132,7 +132,7 @@ TEST(ProcessInfo, Self) {
FromPointerCast<WinVMAddress>(_ReturnAddress()));
}
void TestOtherProcess(const base::FilePath& directory) {
void TestOtherProcess(TestPaths::Architecture architecture) {
ProcessInfo process_info;
UUID done_uuid;
@ -142,15 +142,11 @@ void TestOtherProcess(const base::FilePath& directory) {
CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent");
std::wstring child_test_executable =
directory
.Append(TestPaths::Executable()
.BaseName()
.RemoveFinalExtension()
.value() +
L"_process_info_test_child.exe")
.value();
base::FilePath child_test_executable =
TestPaths::BuildArtifact(L"util",
L"process_info_test_child",
TestPaths::FileType::kExecutable,
architecture);
std::wstring args;
AppendCommandLineArgument(done_uuid.ToString16(), &args);
@ -191,17 +187,16 @@ void TestOtherProcess(const base::FilePath& directory) {
}
TEST(ProcessInfo, OtherProcess) {
TestOtherProcess(TestPaths::Executable().DirName());
TestOtherProcess(TestPaths::Architecture::kDefault);
}
#if defined(ARCH_CPU_64_BITS)
TEST(ProcessInfo, OtherProcessWOW64) {
base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
if (output_32_bit_directory.empty()) {
if (!TestPaths::Has32BitBuildArtifacts()) {
DISABLED_TEST();
}
TestOtherProcess(output_32_bit_directory);
TestOtherProcess(TestPaths::Architecture::k32Bit);
}
#endif // ARCH_CPU_64_BITS

View File

@ -163,14 +163,11 @@ TEST(SafeTerminateProcess, PatchBadly) {
}
TEST(SafeTerminateProcess, TerminateChild) {
base::FilePath test_executable = TestPaths::Executable();
std::wstring child_executable =
test_executable.DirName()
.Append(test_executable.BaseName().RemoveFinalExtension().value() +
L"_safe_terminate_process_test_child.exe")
.value();
ChildLauncher child(child_executable, std::wstring());
base::FilePath child_executable =
TestPaths::BuildArtifact(L"util",
L"safe_terminate_process_test_child",
TestPaths::FileType::kExecutable);
ChildLauncher child(child_executable, L"");
ASSERT_NO_FATAL_FAILURE(child.Start());
constexpr DWORD kExitCode = 0x51ee9d1e; // Sort of like “sleep and die.”