• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BoolToTristate(bool b)30 Tristate BoolToTristate(bool b) {
31   return b ? TRISTATE_TRUE : TRISTATE_FALSE;
32 }
33 
34 class ChannelTest : public testing::Test {
35  public:
ChannelTest()36   ChannelTest()
37       : io_thread_(test::TestIOThread::kAutoStart),
38         init_result_(TRISTATE_UNKNOWN) {}
~ChannelTest()39   virtual ~ChannelTest() {}
40 
SetUp()41   virtual void SetUp() OVERRIDE {
42     io_thread_.PostTaskAndWait(
43         FROM_HERE,
44         base::Bind(&ChannelTest::SetUpOnIOThread, base::Unretained(this)));
45   }
46 
CreateChannelOnIOThread()47   void CreateChannelOnIOThread() {
48     CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
49     channel_ = new Channel();
50   }
51 
InitChannelOnIOThread()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 
ShutdownChannelOnIOThread()62   void ShutdownChannelOnIOThread() {
63     CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
64 
65     CHECK(channel_);
66     channel_->Shutdown();
67   }
68 
io_thread()69   test::TestIOThread* io_thread() { return &io_thread_; }
raw_channel()70   RawChannel* raw_channel() { return raw_channel_.get(); }
mutable_raw_channel()71   scoped_ptr<RawChannel>* mutable_raw_channel() { return &raw_channel_; }
channel()72   Channel* channel() { return channel_.get(); }
mutable_channel()73   scoped_refptr<Channel>* mutable_channel() { return &channel_; }
init_result() const74   Tristate init_result() const { return init_result_; }
75 
76  private:
SetUpOnIOThread()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 
TEST_F(ChannelTest,InitShutdown)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:
MockRawChannelOnInitFails()124   MockRawChannelOnInitFails() : on_init_called_(false) {}
~MockRawChannelOnInitFails()125   virtual ~MockRawChannelOnInitFails() {}
126 
127   // |RawChannel| public methods:
GetSerializedPlatformHandleSize() const128   virtual size_t GetSerializedPlatformHandleSize() const OVERRIDE {
129     return 0;
130   }
131 
132  private:
133   // |RawChannel| protected methods:
Read(size_t *)134   virtual IOResult Read(size_t*) OVERRIDE {
135     CHECK(false);
136     return IO_FAILED;
137   }
ScheduleRead()138   virtual IOResult ScheduleRead() OVERRIDE {
139     CHECK(false);
140     return IO_FAILED;
141   }
GetReadPlatformHandles(size_t,const void *)142   virtual embedder::ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
143       size_t, const void*) OVERRIDE {
144     CHECK(false);
145     return embedder::ScopedPlatformHandleVectorPtr();
146   }
WriteNoLock(size_t *,size_t *)147   virtual IOResult WriteNoLock(size_t*, size_t*) OVERRIDE {
148     CHECK(false);
149     return IO_FAILED;
150   }
ScheduleWriteNoLock()151   virtual IOResult ScheduleWriteNoLock() OVERRIDE {
152     CHECK(false);
153     return IO_FAILED;
154   }
OnInit()155   virtual bool OnInit() OVERRIDE {
156     EXPECT_FALSE(on_init_called_);
157     on_init_called_ = true;
158     return false;
159   }
OnShutdownNoLock(scoped_ptr<ReadBuffer>,scoped_ptr<WriteBuffer>)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 
TEST_F(ChannelTest,InitFails)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 
TEST_F(ChannelTest,CloseBeforeRun)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 
TEST_F(ChannelTest,ShutdownAfterAttach)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 
TEST_F(ChannelTest,WaitAfterAttachRunAndShutdown)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