blob: bff8eb6a9bc946d9e46e04c007b7d8d52fbc66c2 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/mac/mach_port_broker.h"
#include "base/command_line.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
namespace base {
namespace {
const char kBootstrapPortName[] = "thisisatest";
}
class MachPortBrokerTest : public testing::Test,
public base::PortProvider::Observer {
public:
MachPortBrokerTest()
: broker_(kBootstrapPortName),
event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
received_process_(kNullProcessHandle) {
broker_.AddObserver(this);
}
~MachPortBrokerTest() override {
broker_.RemoveObserver(this);
}
// Helper function to acquire/release locks and call |PlaceholderForPid()|.
void AddPlaceholderForPid(base::ProcessHandle pid) {
base::AutoLock lock(broker_.GetLock());
broker_.AddPlaceholderForPid(pid);
}
// Helper function to acquire/release locks and call |FinalizePid()|.
void FinalizePid(base::ProcessHandle pid,
mach_port_t task_port) {
base::AutoLock lock(broker_.GetLock());
broker_.FinalizePid(pid, task_port);
}
void WaitForTaskPort() {
event_.Wait();
}
// base::PortProvider::Observer:
void OnReceivedTaskPort(ProcessHandle process) override {
received_process_ = process;
event_.Signal();
}
protected:
MachPortBroker broker_;
WaitableEvent event_;
ProcessHandle received_process_;
};
TEST_F(MachPortBrokerTest, Locks) {
// Acquire and release the locks. Nothing bad should happen.
base::AutoLock lock(broker_.GetLock());
}
TEST_F(MachPortBrokerTest, AddPlaceholderAndFinalize) {
// Add a placeholder for PID 1.
AddPlaceholderForPid(1);
EXPECT_EQ(0u, broker_.TaskForPid(1));
// Finalize PID 1.
FinalizePid(1, 100u);
EXPECT_EQ(100u, broker_.TaskForPid(1));
// Should be no entry for PID 2.
EXPECT_EQ(0u, broker_.TaskForPid(2));
}
TEST_F(MachPortBrokerTest, FinalizeUnknownPid) {
// Finalizing an entry for an unknown pid should not add it to the map.
FinalizePid(1u, 100u);
EXPECT_EQ(0u, broker_.TaskForPid(1u));
}
MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild) {
CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName));
return 0;
}
TEST_F(MachPortBrokerTest, ReceivePortFromChild) {
ASSERT_TRUE(broker_.Init());
CommandLine command_line(
base::GetMultiProcessTestChildBaseCommandLine());
broker_.GetLock().Acquire();
base::Process test_child_process = base::SpawnMultiProcessTestChild(
"MachPortBrokerTestChild", command_line, LaunchOptions());
broker_.AddPlaceholderForPid(test_child_process.Handle());
broker_.GetLock().Release();
WaitForTaskPort();
EXPECT_EQ(test_child_process.Handle(), received_process_);
int rv = -1;
ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
TestTimeouts::action_timeout(), &rv));
EXPECT_EQ(0, rv);
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
broker_.TaskForPid(test_child_process.Handle()));
}
TEST_F(MachPortBrokerTest, ReceivePortFromChildWithoutAdding) {
ASSERT_TRUE(broker_.Init());
CommandLine command_line(
base::GetMultiProcessTestChildBaseCommandLine());
broker_.GetLock().Acquire();
base::Process test_child_process = base::SpawnMultiProcessTestChild(
"MachPortBrokerTestChild", command_line, LaunchOptions());
broker_.GetLock().Release();
int rv = -1;
ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
TestTimeouts::action_timeout(), &rv));
EXPECT_EQ(0, rv);
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
broker_.TaskForPid(test_child_process.Handle()));
}
} // namespace base