Index: ipc/ipc_channel_mojo_unittest.cc |
diff --git a/ipc/ipc_channel_mojo_unittest.cc b/ipc/ipc_channel_mojo_unittest.cc |
index e846c132bedc211ddea92863e47718753bafa938..0e085162ca0cc81caa09796ed629b3487fad0bf1 100644 |
--- a/ipc/ipc_channel_mojo_unittest.cc |
+++ b/ipc/ipc_channel_mojo_unittest.cc |
@@ -11,9 +11,12 @@ |
#include <utility> |
#include "base/base_paths.h" |
+#include "base/bind.h" |
#include "base/files/file.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/location.h" |
+#include "base/macros.h" |
+#include "base/message_loop/message_loop.h" |
#include "base/path_service.h" |
#include "base/pickle.h" |
#include "base/run_loop.h" |
@@ -103,6 +106,7 @@ class ChannelClient { |
void Init(mojo::ScopedMessagePipeHandle handle) { |
handle_ = std::move(handle); |
} |
+ |
void Connect(IPC::Listener* listener) { |
channel_ = IPC::ChannelMojo::Create(std::move(handle_), |
IPC::Channel::MODE_CLIENT, listener); |
@@ -126,34 +130,40 @@ class ChannelClient { |
std::unique_ptr<IPC::ChannelMojo> channel_; |
}; |
-class IPCChannelMojoTest : public testing::Test { |
+class IPCChannelMojoTestBase : public testing::Test { |
public: |
- IPCChannelMojoTest() {} |
- |
- void TearDown() override { base::RunLoop().RunUntilIdle(); } |
- |
void InitWithMojo(const std::string& test_client_name) { |
handle_ = helper_.StartChild(test_client_name); |
} |
+ bool WaitForClientShutdown() { return helper_.WaitForChildTestShutdown(); } |
+ |
+ protected: |
+ mojo::ScopedMessagePipeHandle TakeHandle() { return std::move(handle_); } |
+ |
+ private: |
+ mojo::ScopedMessagePipeHandle handle_; |
+ mojo::edk::test::MultiprocessTestHelper helper_; |
+}; |
+ |
+class IPCChannelMojoTest : public IPCChannelMojoTestBase { |
+ public: |
+ void TearDown() override { base::RunLoop().RunUntilIdle(); } |
+ |
void CreateChannel(IPC::Listener* listener) { |
- channel_ = IPC::ChannelMojo::Create(std::move(handle_), |
- IPC::Channel::MODE_SERVER, listener); |
+ channel_ = IPC::ChannelMojo::Create( |
+ TakeHandle(), IPC::Channel::MODE_SERVER, listener); |
} |
bool ConnectChannel() { return channel_->Connect(); } |
void DestroyChannel() { channel_.reset(); } |
- bool WaitForClientShutdown() { return helper_.WaitForChildTestShutdown(); } |
- |
IPC::Sender* sender() { return channel(); } |
IPC::Channel* channel() { return channel_.get(); } |
private: |
base::MessageLoop message_loop_; |
- mojo::edk::test::MultiprocessTestHelper helper_; |
- mojo::ScopedMessagePipeHandle handle_; |
std::unique_ptr<IPC::Channel> channel_; |
}; |
@@ -699,7 +709,176 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SimpleAssociatedInterfaceClient, |
Close(); |
} |
+class ChannelProxyRunner { |
+ public: |
+ ChannelProxyRunner(std::unique_ptr<IPC::ChannelFactory> channel_factory) |
+ : channel_factory_(std::move(channel_factory)), |
+ io_thread_("ChannelProxyRunner IO thread") { |
+ } |
+ |
+ void CreateProxy(IPC::Listener* listener) { |
+ io_thread_.StartWithOptions( |
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
+ proxy_.reset(new IPC::ChannelProxy(listener, io_thread_.task_runner())); |
+ } |
+ void RunProxy() { proxy_->Init(std::move(channel_factory_), true); } |
+ |
+ IPC::ChannelProxy* proxy() { return proxy_.get(); } |
+ |
+ private: |
+ std::unique_ptr<IPC::ChannelFactory> channel_factory_; |
+ |
+ base::Thread io_thread_; |
+ std::unique_ptr<IPC::ChannelProxy> proxy_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ChannelProxyRunner); |
+}; |
+ |
+class IPCChannelProxyMojoTest : public IPCChannelMojoTestBase { |
+ public: |
+ void InitWithMojo(const std::string& client_name) { |
+ IPCChannelMojoTestBase::InitWithMojo(client_name); |
+ runner_.reset(new ChannelProxyRunner( |
+ IPC::ChannelMojo::CreateServerFactory(TakeHandle()))); |
+ } |
+ void CreateProxy(IPC::Listener* listener) { runner_->CreateProxy(listener); } |
+ void RunProxy() { runner_->RunProxy(); } |
+ |
+ IPC::ChannelProxy* proxy() { return runner_->proxy(); } |
+ |
+ private: |
+ base::MessageLoop message_loop_; |
+ std::unique_ptr<ChannelProxyRunner> runner_; |
+}; |
+ |
+class ListenerWithSimpleProxyAssociatedInterface |
+ : public IPC::Listener, |
+ public IPC::mojom::SimpleTestDriver { |
+ public: |
+ static const int kNumMessages; |
+ |
+ ListenerWithSimpleProxyAssociatedInterface() : binding_(this) {} |
+ |
+ ~ListenerWithSimpleProxyAssociatedInterface() override {} |
+ |
+ bool OnMessageReceived(const IPC::Message& message) override { |
+ base::PickleIterator iter(message); |
+ std::string should_be_expected; |
+ EXPECT_TRUE(iter.ReadString(&should_be_expected)); |
+ EXPECT_EQ(should_be_expected, next_expected_string_); |
+ num_messages_received_++; |
+ return true; |
+ } |
+ |
+ void OnChannelError() override { |
+ DCHECK(received_quit_); |
+ } |
+ |
+ void RegisterInterfaceFactory(IPC::ChannelProxy* proxy) { |
+ proxy->AddAssociatedInterface( |
+ base::Bind(&ListenerWithSimpleProxyAssociatedInterface::BindRequest, |
+ base::Unretained(this))); |
+ } |
+ |
+ bool received_all_messages() const { |
+ return num_messages_received_ == kNumMessages && received_quit_; |
+ } |
+ |
+ private: |
+ // IPC::mojom::SimpleTestDriver: |
+ void ExpectString(const mojo::String& str) override { |
+ next_expected_string_ = str; |
+ } |
+ |
+ void RequestQuit(const RequestQuitCallback& callback) override { |
+ received_quit_ = true; |
+ callback.Run(); |
+ base::MessageLoop::current()->QuitWhenIdle(); |
+ } |
+ |
+ void BindRequest(IPC::mojom::SimpleTestDriverAssociatedRequest request) { |
+ DCHECK(!binding_.is_bound()); |
+ binding_.Bind(std::move(request)); |
+ } |
+ |
+ std::string next_expected_string_; |
+ int num_messages_received_ = 0; |
+ bool received_quit_ = false; |
+ |
+ mojo::AssociatedBinding<IPC::mojom::SimpleTestDriver> binding_; |
+}; |
+ |
+const int ListenerWithSimpleProxyAssociatedInterface::kNumMessages = 1000; |
+ |
+TEST_F(IPCChannelProxyMojoTest, ProxyThreadAssociatedInterface) { |
+ InitWithMojo("ProxyThreadAssociatedInterfaceClient"); |
+ |
+ ListenerWithSimpleProxyAssociatedInterface listener; |
+ CreateProxy(&listener); |
+ listener.RegisterInterfaceFactory(proxy()); |
+ RunProxy(); |
+ |
+ base::RunLoop().Run(); |
+ |
+ EXPECT_TRUE(WaitForClientShutdown()); |
+ EXPECT_TRUE(listener.received_all_messages()); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+class ChannelProxyClient { |
+ public: |
+ void Init(mojo::ScopedMessagePipeHandle handle) { |
+ runner_.reset(new ChannelProxyRunner( |
+ IPC::ChannelMojo::CreateClientFactory(std::move(handle)))); |
+ } |
+ void CreateProxy(IPC::Listener* listener) { runner_->CreateProxy(listener); } |
+ void RunProxy() { runner_->RunProxy(); } |
+ |
+ IPC::ChannelProxy* proxy() { return runner_->proxy(); } |
+ |
+ private: |
+ base::MessageLoop message_loop_; |
+ std::unique_ptr<ChannelProxyRunner> runner_; |
+}; |
+ |
+class ListenerThatWaitsForConnect : public IPC::Listener { |
+ public: |
+ explicit ListenerThatWaitsForConnect(const base::Closure& connect_handler) |
+ : connect_handler_(connect_handler) {} |
+ |
+ // IPC::Listener |
+ bool OnMessageReceived(const IPC::Message& message) override { return true; } |
+ void OnChannelConnected(int32_t) override { connect_handler_.Run(); } |
+ |
+ private: |
+ base::Closure connect_handler_; |
+}; |
+ |
+DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(ProxyThreadAssociatedInterfaceClient, |
+ ChannelProxyClient) { |
+ base::RunLoop connect_loop; |
+ ListenerThatWaitsForConnect listener(connect_loop.QuitClosure()); |
+ CreateProxy(&listener); |
+ RunProxy(); |
+ connect_loop.Run(); |
+ |
+ // Send a bunch of interleaved messages, alternating between the associated |
+ // interface and a legacy IPC::Message. |
+ IPC::mojom::SimpleTestDriverAssociatedPtr driver; |
+ proxy()->GetRemoteAssociatedInterface(&driver); |
+ for (int i = 0; i < ListenerWithSimpleProxyAssociatedInterface::kNumMessages; |
+ ++i) { |
+ std::string str = base::StringPrintf("Hello! %d", i); |
+ driver->ExpectString(str); |
+ SendString(proxy(), str); |
+ } |
+ driver->RequestQuit(base::MessageLoop::QuitWhenIdleClosure()); |
+ base::RunLoop().Run(); |
+} |
+ |
#if defined(OS_POSIX) |
+ |
class ListenerThatExpectsFile : public IPC::Listener { |
public: |
ListenerThatExpectsFile() : sender_(NULL) {} |