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 "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 
     27 Tristate BoolToTristate(bool b) {
     28   return b ? TRISTATE_TRUE : TRISTATE_FALSE;
     29 }
     30 
     31 class ChannelTest : public testing::Test {
     32  public:
     33   ChannelTest()
     34       : io_thread_(base::TestIOThread::kAutoStart),
     35         init_result_(TRISTATE_UNKNOWN) {}
     36   virtual ~ChannelTest() {}
     37 
     38   virtual void SetUp() OVERRIDE {
     39     io_thread_.PostTaskAndWait(
     40         FROM_HERE,
     41         base::Bind(&ChannelTest::SetUpOnIOThread, base::Unretained(this)));
     42   }
     43 
     44   void CreateChannelOnIOThread() {
     45     CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
     46     channel_ = new Channel(&platform_support_);
     47   }
     48 
     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 
     59   void ShutdownChannelOnIOThread() {
     60     CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
     61 
     62     CHECK(channel_.get());
     63     channel_->Shutdown();
     64   }
     65 
     66   base::TestIOThread* io_thread() { return &io_thread_; }
     67   RawChannel* raw_channel() { return raw_channel_.get(); }
     68   scoped_ptr<RawChannel>* mutable_raw_channel() { return &raw_channel_; }
     69   Channel* channel() { return channel_.get(); }
     70   scoped_refptr<Channel>* mutable_channel() { return &channel_; }
     71   Tristate init_result() const { return init_result_; }
     72 
     73  private:
     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 
     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:
    120   MockRawChannelOnInitFails() : on_init_called_(false) {}
    121   virtual ~MockRawChannelOnInitFails() {}
    122 
    123   // |RawChannel| public methods:
    124   virtual size_t GetSerializedPlatformHandleSize() const OVERRIDE { return 0; }
    125 
    126  private:
    127   // |RawChannel| protected methods:
    128   virtual IOResult Read(size_t*) OVERRIDE {
    129     CHECK(false);
    130     return IO_FAILED_UNKNOWN;
    131   }
    132   virtual IOResult ScheduleRead() OVERRIDE {
    133     CHECK(false);
    134     return IO_FAILED_UNKNOWN;
    135   }
    136   virtual embedder::ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
    137       size_t,
    138       const void*) OVERRIDE {
    139     CHECK(false);
    140     return embedder::ScopedPlatformHandleVectorPtr();
    141   }
    142   virtual IOResult WriteNoLock(size_t*, size_t*) OVERRIDE {
    143     CHECK(false);
    144     return IO_FAILED_UNKNOWN;
    145   }
    146   virtual IOResult ScheduleWriteNoLock() OVERRIDE {
    147     CHECK(false);
    148     return IO_FAILED_UNKNOWN;
    149   }
    150   virtual bool OnInit() OVERRIDE {
    151     EXPECT_FALSE(on_init_called_);
    152     on_init_called_ = true;
    153     return false;
    154   }
    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 
    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 
    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 
    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 
    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