| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(vtl): Enable this on non-POSIX once we have a non-POSIX implementation. | 5 // TODO(vtl): Enable this on non-POSIX once we have a non-POSIX implementation. |
| 6 #include "build/build_config.h" | 6 #include "build/build_config.h" |
| 7 #if defined(OS_POSIX) | 7 #if defined(OS_POSIX) |
| 8 | 8 |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| 11 #include <string> | 11 #include <string> |
| 12 | 12 |
| 13 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/callback.h" | 15 #include "base/callback.h" |
| 16 #include "base/location.h" | 16 #include "base/location.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 19 #include "base/threading/thread.h" | 19 #include "base/threading/thread.h" |
| 20 #include "mojo/common/test/multiprocess_test_base.h" | 20 #include "mojo/common/test/multiprocess_test_helper.h" |
| 21 #include "mojo/system/channel.h" | 21 #include "mojo/system/channel.h" |
| 22 #include "mojo/system/embedder/scoped_platform_handle.h" | 22 #include "mojo/system/embedder/scoped_platform_handle.h" |
| 23 #include "mojo/system/local_message_pipe_endpoint.h" | 23 #include "mojo/system/local_message_pipe_endpoint.h" |
| 24 #include "mojo/system/message_pipe.h" | 24 #include "mojo/system/message_pipe.h" |
| 25 #include "mojo/system/proxy_message_pipe_endpoint.h" | 25 #include "mojo/system/proxy_message_pipe_endpoint.h" |
| 26 #include "mojo/system/test_utils.h" | 26 #include "mojo/system/test_utils.h" |
| 27 #include "mojo/system/waiter.h" | 27 #include "mojo/system/waiter.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" |
| 28 | 29 |
| 29 namespace mojo { | 30 namespace mojo { |
| 30 namespace system { | 31 namespace system { |
| 31 namespace { | 32 namespace { |
| 32 | 33 |
| 34 // TODO(vtl): Replace this with a |TestIOThread|. |
| 33 class IOThreadWrapper { | 35 class IOThreadWrapper { |
| 34 public: | 36 public: |
| 35 IOThreadWrapper() : io_thread_("io_thread") {} | 37 IOThreadWrapper() : io_thread_("io_thread") {} |
| 36 ~IOThreadWrapper() { | 38 ~IOThreadWrapper() { |
| 37 CHECK(!channel_.get()); | 39 CHECK(!channel_.get()); |
| 38 CHECK(!io_thread_.IsRunning()); | 40 CHECK(!io_thread_.IsRunning()); |
| 39 } | 41 } |
| 40 | 42 |
| 41 void PostTask(const tracked_objects::Location& from_here, | 43 void PostTask(const tracked_objects::Location& from_here, |
| 42 const base::Closure& task) { | 44 const base::Closure& task) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 channel_->Shutdown(); | 105 channel_->Shutdown(); |
| 104 channel_ = NULL; | 106 channel_ = NULL; |
| 105 } | 107 } |
| 106 | 108 |
| 107 base::Thread io_thread_; | 109 base::Thread io_thread_; |
| 108 scoped_refptr<Channel> channel_; | 110 scoped_refptr<Channel> channel_; |
| 109 | 111 |
| 110 DISALLOW_COPY_AND_ASSIGN(IOThreadWrapper); | 112 DISALLOW_COPY_AND_ASSIGN(IOThreadWrapper); |
| 111 }; | 113 }; |
| 112 | 114 |
| 113 class MultiprocessMessagePipeTest : public mojo::test::MultiprocessTestBase { | 115 class MultiprocessMessagePipeTest : public testing::Test { |
| 114 public: | 116 public: |
| 115 MultiprocessMessagePipeTest() {} | 117 MultiprocessMessagePipeTest() {} |
| 116 virtual ~MultiprocessMessagePipeTest() {} | 118 virtual ~MultiprocessMessagePipeTest() {} |
| 117 | 119 |
| 118 virtual void TearDown() OVERRIDE { | 120 virtual void TearDown() OVERRIDE { |
| 119 if (io_thread_wrapper_.is_initialized()) | 121 if (io_thread_wrapper_.is_initialized()) |
| 120 io_thread_wrapper_.Shutdown(); | 122 io_thread_wrapper_.Shutdown(); |
| 121 mojo::test::MultiprocessTestBase::TearDown(); | |
| 122 } | 123 } |
| 123 | 124 |
| 125 protected: |
| 124 void Init(scoped_refptr<MessagePipe> mp) { | 126 void Init(scoped_refptr<MessagePipe> mp) { |
| 125 io_thread_wrapper_.Init(server_platform_handle.Pass(), mp); | 127 io_thread_wrapper_.Init(helper_.server_platform_handle.Pass(), mp); |
| 126 } | 128 } |
| 127 | 129 |
| 130 mojo::test::MultiprocessTestHelper* helper() { return &helper_; } |
| 131 |
| 128 private: | 132 private: |
| 129 IOThreadWrapper io_thread_wrapper_; | 133 IOThreadWrapper io_thread_wrapper_; |
| 134 mojo::test::MultiprocessTestHelper helper_; |
| 130 | 135 |
| 131 DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTest); | 136 DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTest); |
| 132 }; | 137 }; |
| 133 | 138 |
| 134 MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) { | 139 MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) { |
| 135 Waiter waiter; | 140 Waiter waiter; |
| 136 waiter.Init(); | 141 waiter.Init(); |
| 137 | 142 |
| 138 MojoResult add_result = mp->AddWaiter(0, &waiter, flags, MOJO_RESULT_OK); | 143 MojoResult add_result = mp->AddWaiter(0, &waiter, flags, MOJO_RESULT_OK); |
| 139 if (add_result != MOJO_RESULT_OK) { | 144 if (add_result != MOJO_RESULT_OK) { |
| 140 return (add_result == MOJO_RESULT_ALREADY_EXISTS) ? MOJO_RESULT_OK : | 145 return (add_result == MOJO_RESULT_ALREADY_EXISTS) ? MOJO_RESULT_OK : |
| 141 add_result; | 146 add_result; |
| 142 } | 147 } |
| 143 | 148 |
| 144 MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE); | 149 MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE); |
| 145 mp->RemoveWaiter(0, &waiter); | 150 mp->RemoveWaiter(0, &waiter); |
| 146 return wait_result; | 151 return wait_result; |
| 147 } | 152 } |
| 148 | 153 |
| 149 // For each message received, sends a reply message with the same contents | 154 // For each message received, sends a reply message with the same contents |
| 150 // repeated twice, until the other end is closed or it receives "quitquitquit" | 155 // repeated twice, until the other end is closed or it receives "quitquitquit" |
| 151 // (which it doesn't reply to). It'll return the number of messages received, | 156 // (which it doesn't reply to). It'll return the number of messages received, |
| 152 // not including any "quitquitquit" message, modulo 100. | 157 // not including any "quitquitquit" message, modulo 100. |
| 153 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { | 158 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { |
| 154 IOThreadWrapper io_thread_wrapper; | 159 IOThreadWrapper io_thread_wrapper; |
| 155 embedder::ScopedPlatformHandle client_platform_handle = | 160 embedder::ScopedPlatformHandle client_platform_handle = |
| 156 MultiprocessMessagePipeTest::client_platform_handle.Pass(); | 161 mojo::test::MultiprocessTestHelper::client_platform_handle.Pass(); |
| 157 CHECK(client_platform_handle.is_valid()); | 162 CHECK(client_platform_handle.is_valid()); |
| 158 scoped_refptr<MessagePipe> mp(new MessagePipe( | 163 scoped_refptr<MessagePipe> mp(new MessagePipe( |
| 159 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), | 164 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), |
| 160 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); | 165 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); |
| 161 io_thread_wrapper.Init(client_platform_handle.Pass(), mp); | 166 io_thread_wrapper.Init(client_platform_handle.Pass(), mp); |
| 162 | 167 |
| 163 const std::string quitquitquit("quitquitquit"); | 168 const std::string quitquitquit("quitquitquit"); |
| 164 int rv = 0; | 169 int rv = 0; |
| 165 for (;; rv = (rv + 1) % 100) { | 170 for (;; rv = (rv + 1) % 100) { |
| 166 // Wait for our end of the message pipe to be readable. | 171 // Wait for our end of the message pipe to be readable. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 196 } | 201 } |
| 197 | 202 |
| 198 | 203 |
| 199 mp->Close(0); | 204 mp->Close(0); |
| 200 io_thread_wrapper.Shutdown(); | 205 io_thread_wrapper.Shutdown(); |
| 201 return rv; | 206 return rv; |
| 202 } | 207 } |
| 203 | 208 |
| 204 // Sends "hello" to child, and expects "hellohello" back. | 209 // Sends "hello" to child, and expects "hellohello" back. |
| 205 TEST_F(MultiprocessMessagePipeTest, Basic) { | 210 TEST_F(MultiprocessMessagePipeTest, Basic) { |
| 206 StartChild("EchoEcho"); | 211 helper()->StartChild("EchoEcho"); |
| 207 | 212 |
| 208 scoped_refptr<MessagePipe> mp(new MessagePipe( | 213 scoped_refptr<MessagePipe> mp(new MessagePipe( |
| 209 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), | 214 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), |
| 210 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); | 215 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); |
| 211 Init(mp); | 216 Init(mp); |
| 212 | 217 |
| 213 std::string hello("hello"); | 218 std::string hello("hello"); |
| 214 EXPECT_EQ(MOJO_RESULT_OK, | 219 EXPECT_EQ(MOJO_RESULT_OK, |
| 215 mp->WriteMessage(0, | 220 mp->WriteMessage(0, |
| 216 hello.data(), static_cast<uint32_t>(hello.size()), | 221 hello.data(), static_cast<uint32_t>(hello.size()), |
| 217 NULL, | 222 NULL, |
| 218 MOJO_WRITE_MESSAGE_FLAG_NONE)); | 223 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 219 | 224 |
| 220 EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE)); | 225 EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE)); |
| 221 | 226 |
| 222 std::string read_buffer(1000, '\0'); | 227 std::string read_buffer(1000, '\0'); |
| 223 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); | 228 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
| 224 CHECK_EQ(mp->ReadMessage(0, | 229 CHECK_EQ(mp->ReadMessage(0, |
| 225 &read_buffer[0], &read_buffer_size, | 230 &read_buffer[0], &read_buffer_size, |
| 226 NULL, NULL, | 231 NULL, NULL, |
| 227 MOJO_READ_MESSAGE_FLAG_NONE), | 232 MOJO_READ_MESSAGE_FLAG_NONE), |
| 228 MOJO_RESULT_OK); | 233 MOJO_RESULT_OK); |
| 229 read_buffer.resize(read_buffer_size); | 234 read_buffer.resize(read_buffer_size); |
| 230 VLOG(2) << "Parent got: " << read_buffer; | 235 VLOG(2) << "Parent got: " << read_buffer; |
| 231 EXPECT_EQ(hello + hello, read_buffer); | 236 EXPECT_EQ(hello + hello, read_buffer); |
| 232 | 237 |
| 233 mp->Close(0); | 238 mp->Close(0); |
| 234 | 239 |
| 235 // We sent one message. | 240 // We sent one message. |
| 236 EXPECT_EQ(1 % 100, WaitForChildShutdown()); | 241 EXPECT_EQ(1 % 100, helper()->WaitForChildShutdown()); |
| 237 } | 242 } |
| 238 | 243 |
| 239 // Sends a bunch of messages to the child. Expects them "repeated" back. Waits | 244 // Sends a bunch of messages to the child. Expects them "repeated" back. Waits |
| 240 // for the child to close its end before quitting. | 245 // for the child to close its end before quitting. |
| 241 TEST_F(MultiprocessMessagePipeTest, QueueMessages) { | 246 TEST_F(MultiprocessMessagePipeTest, QueueMessages) { |
| 242 StartChild("EchoEcho"); | 247 helper()->StartChild("EchoEcho"); |
| 243 | 248 |
| 244 scoped_refptr<MessagePipe> mp(new MessagePipe( | 249 scoped_refptr<MessagePipe> mp(new MessagePipe( |
| 245 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), | 250 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), |
| 246 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); | 251 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); |
| 247 Init(mp); | 252 Init(mp); |
| 248 | 253 |
| 249 static const size_t kNumMessages = 1001; | 254 static const size_t kNumMessages = 1001; |
| 250 for (size_t i = 0; i < kNumMessages; i++) { | 255 for (size_t i = 0; i < kNumMessages; i++) { |
| 251 std::string write_buffer(i, 'A' + (i % 26)); | 256 std::string write_buffer(i, 'A' + (i % 26)); |
| 252 EXPECT_EQ(MOJO_RESULT_OK, | 257 EXPECT_EQ(MOJO_RESULT_OK, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 280 EXPECT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer); | 285 EXPECT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer); |
| 281 } | 286 } |
| 282 | 287 |
| 283 // Wait for it to become readable, which should fail (since we sent | 288 // Wait for it to become readable, which should fail (since we sent |
| 284 // "quitquitquit"). | 289 // "quitquitquit"). |
| 285 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | 290 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
| 286 WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE)); | 291 WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE)); |
| 287 | 292 |
| 288 mp->Close(0); | 293 mp->Close(0); |
| 289 | 294 |
| 290 EXPECT_EQ(static_cast<int>(kNumMessages % 100), WaitForChildShutdown()); | 295 EXPECT_EQ(static_cast<int>(kNumMessages % 100), |
| 296 helper()->WaitForChildShutdown()); |
| 291 } | 297 } |
| 292 | 298 |
| 293 } // namespace | 299 } // namespace |
| 294 } // namespace system | 300 } // namespace system |
| 295 } // namespace mojo | 301 } // namespace mojo |
| 296 | 302 |
| 297 #endif // defined(OS_POSIX) | 303 #endif // defined(OS_POSIX) |
| OLD | NEW |