mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-14 01:08:01 +08:00
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:
parent
af594c8deb
commit
1669ca2bac
@ -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,
|
||||
|
@ -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()) {
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 that’s
|
||||
// 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)
|
||||
|
@ -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 artifact’s type, used to establish the returned
|
||||
//! path’s extension.
|
||||
//! \param[in] architecture The artifact’s 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);
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.”
|
||||
|
Loading…
x
Reference in New Issue
Block a user