Index: ipc/mojo/ipc_channel_mojo_unittest.cc |
diff --git a/ipc/mojo/ipc_channel_mojo_unittest.cc b/ipc/mojo/ipc_channel_mojo_unittest.cc |
index 8ea828f4fb01f131848f65d431df9dfd4aad7d79..2b9a954567fc32eb6d43149c6fa996794450253d 100644 |
--- a/ipc/mojo/ipc_channel_mojo_unittest.cc |
+++ b/ipc/mojo/ipc_channel_mojo_unittest.cc |
@@ -13,6 +13,7 @@ |
#include "ipc/ipc_message.h" |
#include "ipc/ipc_test_base.h" |
#include "ipc/ipc_test_channel_listener.h" |
+#include "ipc/mojo/ipc_channel_mojo_readers.h" |
#if defined(OS_POSIX) |
#include "base/file_descriptor_posix.h" |
@@ -145,6 +146,131 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) { |
return 0; |
} |
+// Close given handle before use to simulate an error. |
+class ErraticChannelMojo : public IPC::ChannelMojo { |
+ public: |
+ ErraticChannelMojo( |
+ const IPC::ChannelHandle& channel_handle, |
+ IPC::Channel::Mode mode, |
+ IPC::Listener* listener, |
+ scoped_refptr<base::TaskRunner> runner) |
+ : ChannelMojo(channel_handle, mode, listener, runner) { |
+ } |
+ |
+ virtual void OnConnected(mojo::ScopedMessagePipeHandle pipe) { |
+ MojoClose(pipe.get().value()); |
+ OnConnected(pipe.Pass()); |
+ } |
+}; |
+ |
+// Exists to create ErraticChannelMojo. |
+class ErraticChannelFactory : public IPC::ChannelFactory { |
+ public: |
+ explicit ErraticChannelFactory( |
+ const IPC::ChannelHandle& handle, |
+ base::TaskRunner* runner) |
+ : handle_(handle), runner_(runner) { |
+ } |
+ |
+ virtual std::string GetName() const OVERRIDE { |
+ return ""; |
+ } |
+ |
+ virtual scoped_ptr<IPC::Channel> BuildChannel( |
+ IPC::Listener* listener) OVERRIDE { |
+ return scoped_ptr<IPC::Channel>( |
+ new ErraticChannelMojo( |
+ handle_, IPC::Channel::MODE_SERVER, listener, runner_)); |
+ } |
+ |
+ private: |
+ IPC::ChannelHandle handle_; |
+ scoped_refptr<base::TaskRunner> runner_; |
+}; |
+ |
+class ListenerExpectingErrors : public IPC::Listener { |
+ public: |
+ ListenerExpectingErrors() |
+ : has_error_(false) { |
+ } |
+ |
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
+ return true; |
+ } |
+ |
+ virtual void OnChannelError() OVERRIDE { |
+ has_error_ = true; |
+ base::MessageLoop::current()->Quit(); |
+ } |
+ |
+ bool has_error() const { return has_error_; } |
+ |
+ private: |
+ bool has_error_; |
+}; |
+ |
+ |
+class IPCChannelMojoErrorTest : public IPCTestBase { |
+ protected: |
+ virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( |
+ const IPC::ChannelHandle& handle, |
+ base::TaskRunner* runner) OVERRIDE { |
+ return scoped_ptr<IPC::ChannelFactory>( |
+ new ErraticChannelFactory(handle, runner)); |
+ } |
+}; |
+ |
+class ListenerThatQuits : public IPC::Listener { |
+ public: |
+ ListenerThatQuits() { |
+ } |
+ |
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
+ return true; |
+ } |
+ |
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { |
+ base::MessageLoop::current()->Quit(); |
+ } |
+}; |
+ |
+// A long running process that connects to us. |
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) { |
+ ListenerThatQuits listener; |
+ ChannelClient client(&listener, "IPCChannelMojoErraticTestClient"); |
+ client.Connect(); |
+ |
+ base::MessageLoop::current()->Run(); |
+ |
+ return 0; |
+} |
+ |
+TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) { |
+ Init("IPCChannelMojoErraticTestClient"); |
+ |
+ // Set up IPC channel and start client. |
+ ListenerExpectingErrors listener; |
+ CreateChannel(&listener); |
+ ASSERT_TRUE(ConnectChannel()); |
+ |
+ // This messages are queued as pending. |
+ for (size_t i = 0; i < 2; ++i) { |
+ IPC::TestChannelListener::SendOneMessage( |
+ sender(), "hello from parent"); |
+ } |
+ |
+ ASSERT_TRUE(StartClient()); |
+ base::MessageLoop::current()->Run(); |
+ |
+ this->channel()->Close(); |
+ |
+ EXPECT_TRUE(WaitForClientShutdown()); |
+ EXPECT_TRUE(listener.has_error()); |
+ |
+ DestroyChannel(); |
+} |
+ |
+ |
#if defined(OS_POSIX) |
class ListenerThatExpectsFile : public IPC::Listener { |
public: |