Home | History | Annotate | Download | only in system
      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