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