#ifndef MOJO_CORE_TEST_MOJO_TEST_BASE_H_
#define MOJO_CORE_TEST_MOJO_TEST_BASE_H_
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include "base/functional/bind.h"
#include "build/blink_buildflags.h"
#include "build/build_config.h"
#include "mojo/core/test/multiprocess_test_helper.h"
#include "mojo/public/c/system/trap.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace core {
namespace test {
class MojoTestBase : public testing::Test {
public:
static constexpr size_t kMaxMessageSizeInTests = 32 * 1024 * 1024;
MojoTestBase();
MojoTestBase(const MojoTestBase&) = delete;
MojoTestBase& operator=(const MojoTestBase&) = delete;
~MojoTestBase() override;
using LaunchType = MultiprocessTestHelper::LaunchType;
class ClientController {
public:
ClientController(const std::string& client_name,
MojoTestBase* test,
LaunchType launch_type);
ClientController(const ClientController&) = delete;
ClientController& operator=(const ClientController&) = delete;
~ClientController();
#if BUILDFLAG(USE_BLINK)
const base::Process& process() const { return helper_.test_child(); }
#endif
MojoHandle pipe() const { return pipe_.get().value(); }
int WaitForShutdown();
private:
friend class MojoTestBase;
#if BUILDFLAG(USE_BLINK)
MultiprocessTestHelper helper_;
#endif
ScopedMessagePipeHandle pipe_;
bool was_shutdown_ = false;
};
ClientController& StartClient(const std::string& client_name);
template <typename HandlerFunc>
void RunTestClient(const std::string& client_name, HandlerFunc handler) {
EXPECT_EQ(0, RunTestClientAndGetExitCode(client_name, handler));
}
template <typename HandlerFunc>
int RunTestClientAndGetExitCode(const std::string& client_name,
HandlerFunc handler) {
ClientController& c = StartClient(client_name);
handler(c.pipe());
return c.WaitForShutdown();
}
template <typename HandlerFunc>
void RunTestClientWithController(const std::string& client_name,
HandlerFunc handler) {
ClientController& c = StartClient(client_name);
handler(c);
EXPECT_EQ(0, c.WaitForShutdown());
}
static void CloseHandle(MojoHandle h);
static void CreateMessagePipe(MojoHandle* p0, MojoHandle* p1);
static void WriteMessageWithHandles(MojoHandle mp,
const std::string& message,
const MojoHandle* handles,
uint32_t num_handles);
static void WriteMessage(MojoHandle mp, const std::string& message);
static std::string ReadMessageWithHandles(MojoHandle mp,
MojoHandle* handles,
uint32_t expected_num_handles);
static std::string ReadMessageWithOptionalHandle(MojoHandle mp,
MojoHandle* handle);
static std::string ReadMessage(MojoHandle mp);
static void ReadMessage(MojoHandle mp, char* data, size_t num_bytes);
static void VerifyTransmission(MojoHandle in,
MojoHandle out,
const std::string& message);
static void VerifyEcho(MojoHandle mp, const std::string& message);
static MojoHandle CreateBuffer(uint64_t size);
static MojoHandle DuplicateBuffer(MojoHandle h, bool read_only);
static void WriteToBuffer(MojoHandle h,
size_t offset,
const std::string_view& s);
static void ExpectBufferContents(MojoHandle h,
size_t offset,
const std::string_view& s);
static void CreateDataPipe(MojoHandle* producer,
MojoHandle* consumer,
size_t capacity);
static void WriteData(MojoHandle producer, const std::string& data);
static std::string ReadData(MojoHandle consumer, size_t size);
static MojoHandleSignalsState GetSignalsState(MojoHandle handle);
static MojoResult WaitForSignals(MojoHandle handle,
MojoHandleSignals signals,
MojoTriggerCondition condition,
MojoHandleSignalsState* state = nullptr);
static MojoResult WaitForSignals(MojoHandle handle,
MojoHandleSignals signals,
MojoHandleSignalsState* state = nullptr);
void set_launch_type(LaunchType launch_type) { launch_type_ = launch_type; }
private:
friend class ClientController;
std::vector<std::unique_ptr<ClientController>> clients_;
LaunchType launch_type_ = LaunchType::CHILD;
};
#if BUILDFLAG(USE_BLINK)
#define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name) \
class client_name##_MainFixture : public test_base { \
void TestBody() override {} \
\
public: \
int Main(MojoHandle); \
}; \
MULTIPROCESS_TEST_MAIN_WITH_SETUP( \
client_name##TestChildMain, \
::mojo::core::test::MultiprocessTestHelper::ChildSetup) { \
client_name##_MainFixture test; \
return ::mojo::core::test::MultiprocessTestHelper::RunClientMain( \
base::BindOnce(&client_name##_MainFixture::Main, \
base::Unretained(&test))); \
} \
int client_name##_MainFixture::Main(MojoHandle pipe_name)
#define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name) \
class client_name##_MainFixture : public test_base { \
void TestBody() override {} \
\
public: \
void Main(MojoHandle); \
}; \
MULTIPROCESS_TEST_MAIN_WITH_SETUP( \
client_name##TestChildMain, \
::mojo::core::test::MultiprocessTestHelper::ChildSetup) { \
client_name##_MainFixture test; \
return ::mojo::core::test::MultiprocessTestHelper::RunClientTestMain( \
base::BindOnce(&client_name##_MainFixture::Main, \
base::Unretained(&test))); \
} \
void client_name##_MainFixture::Main(MojoHandle pipe_name)
#else
#define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name) \
class client_name##_MainFixture : public test_base { \
void TestBody() override {} \
\
public: \
int Main(MojoHandle); \
}; \
int client_name##_MainFixture::Main(MojoHandle pipe_name)
#define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name) \
class client_name##_MainFixture : public test_base { \
void TestBody() override {} \
\
public: \
void Main(MojoHandle); \
}; \
void client_name##_MainFixture::Main(MojoHandle pipe_name)
#endif
}
}
}
#endif