1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/system/channel.h" 6 7 #include "base/bind.h" 8 #include "base/location.h" 9 #include "base/message_loop/message_loop.h" 10 #include "mojo/embedder/platform_channel_pair.h" 11 #include "mojo/system/local_message_pipe_endpoint.h" 12 #include "mojo/system/message_in_transit.h" 13 #include "mojo/system/message_pipe.h" 14 #include "mojo/system/proxy_message_pipe_endpoint.h" 15 #include "mojo/system/raw_channel.h" 16 #include "mojo/system/test_utils.h" 17 #include "mojo/system/waiter.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace mojo { 21 namespace system { 22 namespace { 23 24 enum Tristate { 25 TRISTATE_UNKNOWN = -1, 26 TRISTATE_FALSE = 0, 27 TRISTATE_TRUE = 1 28 }; 29 30 Tristate BoolToTristate(bool b) { 31 return b ? TRISTATE_TRUE : TRISTATE_FALSE; 32 } 33 34 class ChannelTest : public testing::Test { 35 public: 36 ChannelTest() 37 : io_thread_(test::TestIOThread::kAutoStart), 38 init_result_(TRISTATE_UNKNOWN) {} 39 virtual ~ChannelTest() {} 40 41 virtual void SetUp() OVERRIDE { 42 io_thread_.PostTaskAndWait( 43 FROM_HERE, 44 base::Bind(&ChannelTest::SetUpOnIOThread, base::Unretained(this))); 45 } 46 47 void CreateChannelOnIOThread() { 48 CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop()); 49 channel_ = new Channel(); 50 } 51 52 void InitChannelOnIOThread() { 53 CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop()); 54 55 CHECK(raw_channel_); 56 CHECK(channel_); 57 CHECK_EQ(init_result_, TRISTATE_UNKNOWN); 58 59 init_result_ = BoolToTristate(channel_->Init(raw_channel_.Pass())); 60 } 61 62 void ShutdownChannelOnIOThread() { 63 CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop()); 64 65 CHECK(channel_); 66 channel_->Shutdown(); 67 } 68 69 test::TestIOThread* io_thread() { return &io_thread_; } 70 RawChannel* raw_channel() { return raw_channel_.get(); } 71 scoped_ptr<RawChannel>* mutable_raw_channel() { return &raw_channel_; } 72 Channel* channel() { return channel_.get(); } 73 scoped_refptr<Channel>* mutable_channel() { return &channel_; } 74 Tristate init_result() const { return init_result_; } 75 76 private: 77 void SetUpOnIOThread() { 78 CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop()); 79 80 embedder::PlatformChannelPair channel_pair; 81 raw_channel_ = RawChannel::Create(channel_pair.PassServerHandle()).Pass(); 82 other_platform_handle_ = channel_pair.PassClientHandle(); 83 } 84 85 test::TestIOThread io_thread_; 86 scoped_ptr<RawChannel> raw_channel_; 87 embedder::ScopedPlatformHandle other_platform_handle_; 88 scoped_refptr<Channel> channel_; 89 90 Tristate init_result_; 91 92 DISALLOW_COPY_AND_ASSIGN(ChannelTest); 93 }; 94 95 // ChannelTest.InitShutdown ---------------------------------------------------- 96 97 TEST_F(ChannelTest, InitShutdown) { 98 io_thread()->PostTaskAndWait( 99 FROM_HERE, 100 base::Bind(&ChannelTest::CreateChannelOnIOThread, 101 base::Unretained(this))); 102 ASSERT_TRUE(channel()); 103 104 io_thread()->PostTaskAndWait( 105 FROM_HERE, 106 base::Bind(&ChannelTest::InitChannelOnIOThread, 107 base::Unretained(this))); 108 EXPECT_EQ(TRISTATE_TRUE, init_result()); 109 110 io_thread()->PostTaskAndWait( 111 FROM_HERE, 112 base::Bind(&ChannelTest::ShutdownChannelOnIOThread, 113 base::Unretained(this))); 114 115 // Okay to destroy |Channel| on not-the-I/O-thread. 116 EXPECT_TRUE(channel()->HasOneRef()); 117 *mutable_channel() = NULL; 118 } 119 120 // ChannelTest.InitFails ------------------------------------------------------- 121 122 class MockRawChannelOnInitFails : public RawChannel { 123 public: 124 MockRawChannelOnInitFails() : on_init_called_(false) {} 125 virtual ~MockRawChannelOnInitFails() {} 126 127 // |RawChannel| public methods: 128 virtual size_t GetSerializedPlatformHandleSize() const OVERRIDE { 129 return 0; 130 } 131 132 private: 133 // |RawChannel| protected methods: 134 virtual IOResult Read(size_t*) OVERRIDE { 135 CHECK(false); 136 return IO_FAILED; 137 } 138 virtual IOResult ScheduleRead() OVERRIDE { 139 CHECK(false); 140 return IO_FAILED; 141 } 142 virtual embedder::ScopedPlatformHandleVectorPtr GetReadPlatformHandles( 143 size_t, const void*) OVERRIDE { 144 CHECK(false); 145 return embedder::ScopedPlatformHandleVectorPtr(); 146 } 147 virtual IOResult WriteNoLock(size_t*, size_t*) OVERRIDE { 148 CHECK(false); 149 return IO_FAILED; 150 } 151 virtual IOResult ScheduleWriteNoLock() OVERRIDE { 152 CHECK(false); 153 return IO_FAILED; 154 } 155 virtual bool OnInit() OVERRIDE { 156 EXPECT_FALSE(on_init_called_); 157 on_init_called_ = true; 158 return false; 159 } 160 virtual void OnShutdownNoLock(scoped_ptr<ReadBuffer>, 161 scoped_ptr<WriteBuffer>) OVERRIDE { 162 CHECK(false); 163 } 164 165 bool on_init_called_; 166 167 DISALLOW_COPY_AND_ASSIGN(MockRawChannelOnInitFails); 168 }; 169 170 TEST_F(ChannelTest, InitFails) { 171 io_thread()->PostTaskAndWait( 172 FROM_HERE, 173 base::Bind(&ChannelTest::CreateChannelOnIOThread, 174 base::Unretained(this))); 175 ASSERT_TRUE(channel()); 176 177 ASSERT_TRUE(raw_channel()); 178 mutable_raw_channel()->reset(new MockRawChannelOnInitFails()); 179 180 io_thread()->PostTaskAndWait( 181 FROM_HERE, 182 base::Bind(&ChannelTest::InitChannelOnIOThread, 183 base::Unretained(this))); 184 EXPECT_EQ(TRISTATE_FALSE, init_result()); 185 186 // Should destroy |Channel| with no |Shutdown()| (on not-the-I/O-thread). 187 EXPECT_TRUE(channel()->HasOneRef()); 188 *mutable_channel() = NULL; 189 } 190 191 // ChannelTest.CloseBeforeRun -------------------------------------------------- 192 193 TEST_F(ChannelTest, CloseBeforeRun) { 194 io_thread()->PostTaskAndWait( 195 FROM_HERE, 196 base::Bind(&ChannelTest::CreateChannelOnIOThread, 197 base::Unretained(this))); 198 ASSERT_TRUE(channel()); 199 200 io_thread()->PostTaskAndWait( 201 FROM_HERE, 202 base::Bind(&ChannelTest::InitChannelOnIOThread, 203 base::Unretained(this))); 204 EXPECT_EQ(TRISTATE_TRUE, init_result()); 205 206 scoped_refptr<MessagePipe> mp(new MessagePipe( 207 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), 208 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); 209 210 MessageInTransit::EndpointId local_id = 211 channel()->AttachMessagePipeEndpoint(mp, 1); 212 EXPECT_EQ(Channel::kBootstrapEndpointId, local_id); 213 214 mp->Close(0); 215 216 // TODO(vtl): Currently, the |Close()| above won't detach (since it thinks 217 // we're still expecting a "run" message from the other side), so the 218 // |RunMessagePipeEndpoint()| below will return true. We need to refactor 219 // |AttachMessagePipeEndpoint()| to indicate whether |Run...()| will 220 // necessarily be called or not. (Then, in the case that it may not be called, 221 // this will return false.) 222 EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id, 223 Channel::kBootstrapEndpointId)); 224 225 io_thread()->PostTaskAndWait( 226 FROM_HERE, 227 base::Bind(&ChannelTest::ShutdownChannelOnIOThread, 228 base::Unretained(this))); 229 230 EXPECT_TRUE(channel()->HasOneRef()); 231 } 232 233 // ChannelTest.ShutdownAfterAttachAndRun --------------------------------------- 234 235 TEST_F(ChannelTest, ShutdownAfterAttach) { 236 io_thread()->PostTaskAndWait( 237 FROM_HERE, 238 base::Bind(&ChannelTest::CreateChannelOnIOThread, 239 base::Unretained(this))); 240 ASSERT_TRUE(channel()); 241 242 io_thread()->PostTaskAndWait( 243 FROM_HERE, 244 base::Bind(&ChannelTest::InitChannelOnIOThread, 245 base::Unretained(this))); 246 EXPECT_EQ(TRISTATE_TRUE, init_result()); 247 248 scoped_refptr<MessagePipe> mp(new MessagePipe( 249 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), 250 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); 251 252 MessageInTransit::EndpointId local_id = 253 channel()->AttachMessagePipeEndpoint(mp, 1); 254 EXPECT_EQ(Channel::kBootstrapEndpointId, local_id); 255 256 // TODO(vtl): Currently, we always "expect" a |RunMessagePipeEndpoint()| after 257 // an |AttachMessagePipeEndpoint()| (which is actually incorrect). We need to 258 // refactor |AttachMessagePipeEndpoint()| to indicate whether |Run...()| will 259 // necessarily be called or not. (Then, in the case that it may not be called, 260 // we should test a |Shutdown()| without the |Run...()|.) 261 EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id, 262 Channel::kBootstrapEndpointId)); 263 264 Waiter waiter; 265 waiter.Init(); 266 EXPECT_EQ(MOJO_RESULT_OK, 267 mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123)); 268 269 // Don't wait for the shutdown to run ... 270 io_thread()->PostTask(FROM_HERE, 271 base::Bind(&ChannelTest::ShutdownChannelOnIOThread, 272 base::Unretained(this))); 273 274 // ... since this |Wait()| should fail once the channel is shut down. 275 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 276 waiter.Wait(MOJO_DEADLINE_INDEFINITE, NULL)); 277 mp->RemoveWaiter(0, &waiter); 278 279 mp->Close(0); 280 281 EXPECT_TRUE(channel()->HasOneRef()); 282 } 283 284 // ChannelTest.WaitAfterAttachRunAndShutdown ----------------------------------- 285 286 TEST_F(ChannelTest, WaitAfterAttachRunAndShutdown) { 287 io_thread()->PostTaskAndWait( 288 FROM_HERE, 289 base::Bind(&ChannelTest::CreateChannelOnIOThread, 290 base::Unretained(this))); 291 ASSERT_TRUE(channel()); 292 293 io_thread()->PostTaskAndWait( 294 FROM_HERE, 295 base::Bind(&ChannelTest::InitChannelOnIOThread, 296 base::Unretained(this))); 297 EXPECT_EQ(TRISTATE_TRUE, init_result()); 298 299 scoped_refptr<MessagePipe> mp(new MessagePipe( 300 scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), 301 scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint()))); 302 303 MessageInTransit::EndpointId local_id = 304 channel()->AttachMessagePipeEndpoint(mp, 1); 305 EXPECT_EQ(Channel::kBootstrapEndpointId, local_id); 306 307 EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id, 308 Channel::kBootstrapEndpointId)); 309 310 io_thread()->PostTaskAndWait( 311 FROM_HERE, 312 base::Bind(&ChannelTest::ShutdownChannelOnIOThread, 313 base::Unretained(this))); 314 315 Waiter waiter; 316 waiter.Init(); 317 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 318 mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123)); 319 320 mp->Close(0); 321 322 EXPECT_TRUE(channel()->HasOneRef()); 323 } 324 325 // TODO(vtl): More. ------------------------------------------------------------ 326 327 } // namespace 328 } // namespace system 329 } // namespace mojo 330