blob: 329ae496ff40019ae0ed2c4352952f3f7b703c6f [file] [log] [blame]
// Copyright (c) 2009 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 "content/browser/mach_broker_mac.h"
#include "base/command_line.h"
#include "base/mac/mach_port_broker.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 "content/common/content_constants_internal.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
namespace content {
class MachBrokerTest : public testing::Test,
public base::PortProvider::Observer {
public:
MachBrokerTest()
: event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
received_process_(base::kNullProcessHandle) {
broker_.AddObserver(this);
}
~MachBrokerTest() override {
broker_.RemoveObserver(this);
}
// Helper function to acquire/release locks and call |PlaceholderForPid()|.
void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id) {
base::AutoLock lock(broker_.GetLock());
broker_.AddPlaceholderForPid(pid, child_process_id);
}
void InvalidateChildProcessId(int child_process_id) {
broker_.InvalidateChildProcessId(child_process_id);
}
int GetChildProcessCount(int child_process_id) {
return broker_.child_process_id_map_.count(child_process_id);
}
base::Process LaunchTestChild(const std::string& function,
int child_process_id) {
base::AutoLock lock(broker_.GetLock());
base::Process test_child_process = base::SpawnMultiProcessTestChild(
function, base::GetMultiProcessTestChildBaseCommandLine(),
base::LaunchOptions());
broker_.AddPlaceholderForPid(test_child_process.Handle(), child_process_id);
return test_child_process;
}
void WaitForChildExit(base::Process& process) {
int rv = -1;
ASSERT_TRUE(process.WaitForExitWithTimeout(
TestTimeouts::action_timeout(), &rv));
EXPECT_EQ(0, rv);
}
void WaitForTaskPort() {
event_.Wait();
}
// base::PortProvider::Observer:
void OnReceivedTaskPort(base::ProcessHandle process) override {
received_process_ = process;
event_.Signal();
}
protected:
MachBroker broker_;
base::WaitableEvent event_;
base::ProcessHandle received_process_;
TestBrowserThreadBundle thread_bundle_;
};
MULTIPROCESS_TEST_MAIN(MachBrokerTestChild) {
CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kMachBootstrapName));
return 0;
}
TEST_F(MachBrokerTest, Locks) {
// Acquire and release the locks. Nothing bad should happen.
base::AutoLock lock(broker_.GetLock());
}
TEST_F(MachBrokerTest, AddChildProcess) {
{
base::AutoLock lock(broker_.GetLock());
broker_.EnsureRunning();
}
base::Process child_process = LaunchTestChild("MachBrokerTestChild", 7);
WaitForTaskPort();
EXPECT_EQ(child_process.Handle(), received_process_);
WaitForChildExit(child_process);
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
broker_.TaskForPid(child_process.Handle()));
EXPECT_EQ(1, GetChildProcessCount(7));
// Should be no entry for any other PID.
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
broker_.TaskForPid(child_process.Handle() + 1));
InvalidateChildProcessId(7);
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
broker_.TaskForPid(child_process.Handle()));
EXPECT_EQ(0, GetChildProcessCount(7));
}
} // namespace content