// 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/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.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_(true, false), 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(MachBroker::ChildSendTaskPortToParent()); 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_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_NULL), broker_.TaskForPid(child_process.Handle() + 1)); InvalidateChildProcessId(7); EXPECT_EQ(static_cast(MACH_PORT_NULL), broker_.TaskForPid(child_process.Handle())); EXPECT_EQ(0, GetChildProcessCount(7)); } } // namespace content