blob: e1e05e3c14753df158c6753edd72ea207dd93800 [file] [log] [blame]
// Copyright 2014 The Crashpad Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "build/build_config.h"
#include "test/multiprocess.h"
#include "test/process_type.h"
//! \file
namespace crashpad {
namespace test {
namespace internal {
//! \brief Command line argument used to indicate that a child test function
//! should be run.
constexpr char kChildTestFunction[] = "--child-test-function=";
//! \brief Helper class used by CRASHPAD_CHILD_TEST_MAIN() to insert a child
//! function into the global mapping.
class AppendMultiprocessTest {
AppendMultiprocessTest(const std::string& test_name,
int (*main_function_pointer)());
//! \brief Used to run a child test function by name, registered by
//! \return The exit code of the child process after running the function named
//! by \a test_name. Aborts with a CHECK() if \a test_name wasn't
//! registered.
int CheckedInvokeMultiprocessChild(const std::string& test_name);
} // namespace internal
//! \brief Registers a function that can be invoked as a child process by
//! MultiprocessExec.
//! Used as:
//! \code
//! ... child body ...
//! }
//! \endcode
//! In the main (parent) test body, this function can be run in a child process
//! via MultiprocessExec::SetChildTestMainFunction().
#define CRASHPAD_CHILD_TEST_MAIN(test_main) \
int test_main(); \
namespace { \
::crashpad::test::internal::AppendMultiprocessTest \
AddMultiprocessTest##_##test_main(#test_main, (test_main)); \
} /* namespace */ \
int test_main()
//! \brief Manages an `exec()`-based multiprocess test.
//! These tests are based on `fork()` and `exec()`. The parent process is able
//! to communicate with the child in the same manner as a base-class
//! Multiprocess parent. The read and write pipes appear in the child process on
//! stdin and stdout, respectively.
//! Subclasses are expected to implement the parent in the same was as a
//! base-class Multiprocess parent. The child must be implemented in an
//! executable to be set by SetChildCommand().
class MultiprocessExec : public Multiprocess {
MultiprocessExec(const MultiprocessExec&) = delete;
MultiprocessExec& operator=(const MultiprocessExec&) = delete;
//! \brief Sets the command to `exec()` in the child.
//! This method must be called before the test can be Run().
//! This method is useful when a custom executable is required for the child
//! binary, however, SetChildTestMainFunction() should generally be preferred.
//! \param[in] command The executable’s pathname.
//! \param[in] arguments The command-line arguments to pass to the child
//! 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.
//! \sa SetChildTestMainFunction
void SetChildCommand(const base::FilePath& command,
const std::vector<std::string>* arguments);
//! \brief Calls SetChildCommand() to run a child test main function
//! registered with CRASHPAD_CHILD_TEST_MAIN().
//! This uses the same launch mechanism as SetChildCommand(), but coordinates
//! with test/ to allow for simple registration of a child
//! processes' entry point via the helper macro, rather than needing to create
//! a separate build target.
//! \param[in] function_name The name of the function as passed to
void SetChildTestMainFunction(const std::string& function_name);
//! \brief Returns a ProcessType representing the child process.
//! This method is only valid during the body of MultiprocessParent().
//! \return A platform-specific type representing the child process. This
//! method can fail on macOS because access to a child's task port
//! requires the task_for_pid entitlement.
ProcessType ChildProcess();
// Multiprocess:
void PreFork() override;
// Multiprocess:
void MultiprocessChild() override;
base::FilePath command_;
std::vector<std::string> arguments_;
std::vector<const char*> argv_;
std::wstring command_line_;
} // namespace test
} // namespace crashpad