#include "test/multinode_test.h"
#include <cstring>
#include <map>
#include <optional>
#include <string>
#include <thread>
#include "ipcz/ipcz.h"
#include "reference_drivers/async_reference_driver.h"
#include "reference_drivers/sync_reference_driver.h"
#include "test_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
#include "third_party/abseil-cpp/absl/base/macros.h"
#include "third_party/abseil-cpp/absl/strings/str_cat.h"
#include "third_party/abseil-cpp/absl/strings/str_split.h"
#include "third_party/abseil-cpp/absl/types/span.h"
#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS)
#include "reference_drivers/file_descriptor.h"
#include "reference_drivers/multiprocess_reference_driver.h"
#include "reference_drivers/socket_transport.h"
#include "test/test_child_launcher.h"
#endif
namespace ipcz::test {
namespace {
using TestDriverMap = std::map<std::string, TestDriver*>;
TestDriverMap& GetTestDrivers() { … }
using TestNodeMap = std::map<std::string, TestNodeFactory>;
TestNodeMap& GetTestNodes() { … }
using TestFeatureSetMap = std::map<std::string, std::vector<IpczFeature>>;
const TestFeatureSetMap& GetTestFeatureSets() { … }
struct RegisteredMultinodeTest { … };
std::vector<RegisteredMultinodeTest>& GetRegisteredMultinodeTests() { … }
class InProcessTestNodeController : public TestNode::TestNodeController { … };
class InProcessTestDriverBase : public TestDriver { … };
class SyncTestDriver : public InProcessTestDriverBase { … };
class AsyncTestDriver : public InProcessTestDriverBase { … };
TestDriverRegistration<SyncTestDriver> kRegisterSyncDriver;
TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriver{
internal::kAsyncTestDriverName, AsyncTestDriver::kDefault};
TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriverWithDelegatedAlloc{
internal::kAsyncDelegatedAllocTestDriverName,
AsyncTestDriver::kDelegateAllocation};
TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriverWithForcedBrokering{
internal::kAsyncForcedBrokeringTestDriverName,
AsyncTestDriver::kForceBrokering};
TestDriverRegistration<AsyncTestDriver>
kRegisterAsyncDriverWithDelegatedAllocAndForcedBrokering{
internal::kAsyncDelegatedAllocAndForcedBrokeringTestDriverName,
AsyncTestDriver::kForceBrokeringAndDelegateAllocation};
#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS)
class ChildProcessTestNodeController : public TestNode::TestNodeController {
public:
ChildProcessTestNodeController(TestNode& source, pid_t pid)
: source_(source), pid_(pid) {}
~ChildProcessTestNodeController() override {
ABSL_ASSERT(result_.has_value());
}
bool WaitForShutdown() override {
if (result_.has_value()) {
return *result_;
}
result_ = TestChildLauncher::WaitForSuccessfulProcessTermination(pid_);
return *result_;
}
TransportPair CreateNewTransports() override {
return source_.CreateTransports();
}
TestNode& source_;
const pid_t pid_;
std::optional<bool> result_;
};
class MultiprocessTestDriver : public TestDriver {
public:
const IpczDriver& GetIpczDriver() const override {
return reference_drivers::kMultiprocessReferenceDriver;
}
const char* GetName() const override {
return internal::kMultiprocessTestDriverName;
}
TransportPair CreateTransports(TestNode& source,
bool for_broker_target) const override {
TransportPair transports;
const IpczResult result = GetIpczDriver().CreateTransports(
IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE, IPCZ_NO_FLAGS,
nullptr, &transports.ours, &transports.theirs);
ABSL_ASSERT(result == IPCZ_RESULT_OK);
return transports;
}
Ref<TestNode::TestNodeController> SpawnTestNode(
TestNode& source,
const TestNodeDetails& details,
const std::string& feature_set,
IpczDriverHandle our_transport,
IpczDriverHandle their_transport) override {
reference_drivers::FileDescriptor socket =
reference_drivers::TakeMultiprocessTransportDescriptor(their_transport);
return MakeRefCounted<ChildProcessTestNodeController>(
source,
child_launcher_.Launch(details.name, feature_set, std::move(socket)));
}
IpczConnectNodeFlags GetExtraClientConnectNodeFlags() const override {
return IPCZ_NO_FLAGS;
}
IpczDriverHandle GetClientTestNodeTransport() override {
auto transport = MakeRefCounted<reference_drivers::SocketTransport>(
TestChildLauncher::TakeChildSocketDescriptor());
return reference_drivers::CreateMultiprocessTransport(std::move(transport));
}
private:
TestChildLauncher child_launcher_;
};
TestDriverRegistration<MultiprocessTestDriver> kRegisterMultiprocessDriver;
#endif
}
namespace internal {
const char kSyncTestDriverName[] = …;
const char kAsyncTestDriverName[] = …;
const char kAsyncDelegatedAllocTestDriverName[] = …;
const char kAsyncForcedBrokeringTestDriverName[] = …;
const char kAsyncDelegatedAllocAndForcedBrokeringTestDriverName[] = …;
const char kMultiprocessTestDriverName[] = …;
}
TestDriverRegistrationImpl::TestDriverRegistrationImpl(TestDriver& driver) { … }
TestNode::~TestNode() { … }
const IpczDriver& TestNode::GetDriver() const { … }
void TestNode::Initialize(TestDriver* test_driver,
const std::string& feature_set) { … }
void TestNode::ConnectToParent(absl::Span<IpczHandle> portals,
IpczConnectNodeFlags flags) { … }
void TestNode::ConnectToBroker(absl::Span<IpczHandle> portals) { … }
IpczHandle TestNode::ConnectToParent(IpczConnectNodeFlags flags) { … }
IpczHandle TestNode::ConnectToBroker() { … }
std::pair<IpczHandle, IpczHandle> TestNode::OpenPortals() { … }
IpczHandle TestNode::BoxBlob(std::string_view contents) { … }
std::string TestNode::UnboxBlob(IpczHandle box) { … }
void TestNode::CloseThisNode() { … }
Ref<TestNode::TestNodeController> TestNode::SpawnTestNodeImpl(
const TestNodeDetails& details,
IpczDriverHandle& our_transport) { … }
TransportPair TestNode::CreateTransports() { … }
TransportPair TestNode::CreateBrokerToBrokerTransports() { … }
void TestNode::SetTransport(IpczDriverHandle transport) { … }
int TestNode::RunAsChild(TestDriver* test_driver,
const std::string& feature_set) { … }
void RegisterMultinodeTestNode(std::string_view node_name,
TestNodeFactory factory) { … }
void RegisterMultinodeTest(const char* test_suite_name,
const char* test_name,
const char* filename,
int line,
MultinodeTestFactory factory) { … }
int RunChildProcessTest(const std::string& test_name) { … }
void RegisterMultinodeTests() { … }
}