Home | History | Annotate | Download | only in tests
      1 // Copyright 2017 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/public/cpp/system/wait.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/strings/string_piece.h"
     13 #include "base/threading/platform_thread.h"
     14 #include "base/threading/simple_thread.h"
     15 #include "base/time/time.h"
     16 #include "mojo/public/c/system/types.h"
     17 #include "mojo/public/cpp/system/handle_signals_state.h"
     18 #include "mojo/public/cpp/system/message_pipe.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace mojo {
     22 namespace {
     23 
     24 using WaitTest = testing::Test;
     25 using WaitManyTest = testing::Test;
     26 
     27 void WriteMessage(const ScopedMessagePipeHandle& handle,
     28                   const base::StringPiece& message) {
     29   MojoResult rv = WriteMessageRaw(handle.get(), message.data(),
     30                                   static_cast<uint32_t>(message.size()),
     31                                   nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
     32   CHECK_EQ(MOJO_RESULT_OK, rv);
     33 }
     34 
     35 std::string ReadMessage(const ScopedMessagePipeHandle& handle) {
     36   std::vector<uint8_t> bytes;
     37   MojoResult rv = ReadMessageRaw(handle.get(), &bytes, nullptr,
     38                                  MOJO_READ_MESSAGE_FLAG_NONE);
     39   CHECK_EQ(MOJO_RESULT_OK, rv);
     40   return std::string(bytes.begin(), bytes.end());
     41 }
     42 
     43 class ThreadedRunner : public base::SimpleThread {
     44  public:
     45   explicit ThreadedRunner(const base::Closure& callback)
     46       : SimpleThread("ThreadedRunner"), callback_(callback) {}
     47   ~ThreadedRunner() override { Join(); }
     48 
     49   void Run() override { callback_.Run(); }
     50 
     51  private:
     52   const base::Closure callback_;
     53 
     54   DISALLOW_COPY_AND_ASSIGN(ThreadedRunner);
     55 };
     56 
     57 TEST_F(WaitTest, InvalidArguments) {
     58   Handle invalid_handle;
     59 
     60   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
     61             Wait(invalid_handle, MOJO_HANDLE_SIGNAL_READABLE));
     62 
     63   MessagePipe p;
     64   Handle valid_handles[2] = {p.handle0.get(), p.handle1.get()};
     65   Handle invalid_handles[2];
     66   MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_NONE,
     67                                   MOJO_HANDLE_SIGNAL_NONE};
     68   size_t result_index = 0;
     69   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
     70             WaitMany(invalid_handles, signals, 2, &result_index));
     71   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
     72             WaitMany(nullptr, signals, 2, &result_index));
     73   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
     74             WaitMany(valid_handles, nullptr, 2, &result_index));
     75 }
     76 
     77 TEST_F(WaitTest, Basic) {
     78   MessagePipe p;
     79 
     80   // Write to one end of the pipe and wait on the other.
     81   const char kTestMessage1[] = "how about a nice game of chess?";
     82   WriteMessage(p.handle0, kTestMessage1);
     83   EXPECT_EQ(MOJO_RESULT_OK, Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE));
     84 
     85   // And make sure we can also grab the handle signals state (with both the C
     86   // and C++ library structs.)
     87 
     88   MojoHandleSignalsState c_hss = {0, 0};
     89   EXPECT_EQ(MOJO_RESULT_OK,
     90             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &c_hss));
     91   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
     92             c_hss.satisfied_signals);
     93 
     94   HandleSignalsState hss;
     95   EXPECT_EQ(MOJO_RESULT_OK,
     96             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss));
     97   EXPECT_TRUE(hss.readable() && hss.writable() && !hss.peer_closed());
     98   EXPECT_FALSE(hss.never_readable() || hss.never_writable() ||
     99                hss.never_peer_closed());
    100 
    101   // Now close the writing end and wait for peer closure.
    102 
    103   p.handle0.reset();
    104   EXPECT_EQ(MOJO_RESULT_OK,
    105             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
    106 
    107   // Still readable as there's still a message queued. No longer writable as
    108   // peer closure has been detected.
    109   EXPECT_TRUE(hss.readable() && hss.peer_closed() && !hss.writable());
    110   EXPECT_TRUE(hss.never_writable() && !hss.never_readable() &&
    111               !hss.never_peer_closed());
    112 
    113   // Read the message and wait for readable again. Waiting should fail since
    114   // there are no more messages and the peer is closed.
    115   EXPECT_EQ(kTestMessage1, ReadMessage(p.handle1));
    116   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    117             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss));
    118 
    119   // Sanity check the signals state again.
    120   EXPECT_TRUE(hss.peer_closed() && !hss.readable() && !hss.writable());
    121   EXPECT_TRUE(hss.never_readable() && hss.never_writable() &&
    122               !hss.never_peer_closed());
    123 }
    124 
    125 TEST_F(WaitTest, DelayedWrite) {
    126   MessagePipe p;
    127 
    128   ThreadedRunner write_after_delay(base::Bind(
    129       [](ScopedMessagePipeHandle* handle) {
    130         // Wait a little while, then write a message.
    131         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    132         WriteMessage(*handle, "wakey wakey");
    133       },
    134       &p.handle0));
    135   write_after_delay.Start();
    136 
    137   HandleSignalsState hss;
    138   EXPECT_EQ(MOJO_RESULT_OK,
    139             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss));
    140   EXPECT_TRUE(hss.readable() && hss.writable() && !hss.peer_closed());
    141   EXPECT_TRUE(!hss.never_readable() && !hss.never_writable() &&
    142               !hss.never_peer_closed());
    143 }
    144 
    145 TEST_F(WaitTest, DelayedPeerClosure) {
    146   MessagePipe p;
    147 
    148   ThreadedRunner close_after_delay(base::Bind(
    149       [](ScopedMessagePipeHandle* handle) {
    150         // Wait a little while, then close the handle.
    151         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    152         handle->reset();
    153       },
    154       &p.handle0));
    155   close_after_delay.Start();
    156 
    157   HandleSignalsState hss;
    158   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    159             Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss));
    160   EXPECT_TRUE(!hss.readable() && !hss.writable() && hss.peer_closed());
    161   EXPECT_TRUE(hss.never_readable() && hss.never_writable() &&
    162               !hss.never_peer_closed());
    163 }
    164 
    165 TEST_F(WaitTest, CloseWhileWaiting) {
    166   MessagePipe p;
    167   ThreadedRunner close_after_delay(base::Bind(
    168       [](ScopedMessagePipeHandle* handle) {
    169         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    170         handle->reset();
    171       },
    172       &p.handle0));
    173   close_after_delay.Start();
    174   EXPECT_EQ(MOJO_RESULT_CANCELLED,
    175             Wait(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE));
    176 }
    177 
    178 TEST_F(WaitManyTest, Basic) {
    179   MessagePipe p;
    180 
    181   const char kTestMessage1[] = "hello";
    182   WriteMessage(p.handle0, kTestMessage1);
    183 
    184   // Wait for either handle to become readable. Wait twice, just to verify that
    185   // we can use either the C or C++ signaling state structure for the last
    186   // argument.
    187 
    188   Handle handles[2] = {p.handle0.get(), p.handle1.get()};
    189   MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
    190                                   MOJO_HANDLE_SIGNAL_READABLE};
    191   size_t result_index = 0;
    192   MojoHandleSignalsState c_hss[2];
    193   HandleSignalsState hss[2];
    194 
    195   EXPECT_EQ(MOJO_RESULT_OK,
    196             WaitMany(handles, signals, 2, &result_index, c_hss));
    197   EXPECT_EQ(1u, result_index);
    198   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, c_hss[0].satisfied_signals);
    199   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
    200             c_hss[1].satisfied_signals);
    201 
    202   EXPECT_EQ(MOJO_RESULT_OK, WaitMany(handles, signals, 2, &result_index, hss));
    203   EXPECT_EQ(1u, result_index);
    204   EXPECT_TRUE(!hss[0].readable() && hss[0].writable() && !hss[0].peer_closed());
    205   EXPECT_TRUE(!hss[0].never_readable() && !hss[0].never_writable() &&
    206               !hss[0].never_peer_closed());
    207   EXPECT_TRUE(hss[1].readable() && hss[1].writable() && !hss[1].peer_closed());
    208   EXPECT_TRUE(!hss[1].never_readable() && !hss[1].never_writable() &&
    209               !hss[1].never_peer_closed());
    210 
    211   // Close the writer and read the message. Try to wait again, and it should
    212   // fail due to the conditions being unsatisfiable.
    213 
    214   EXPECT_EQ(kTestMessage1, ReadMessage(p.handle1));
    215   p.handle0.reset();
    216 
    217   // handles[0] is invalid.
    218   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
    219             WaitMany(handles, signals, 2, &result_index, hss));
    220   handles[0] = handles[1];
    221   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    222             WaitMany(handles, signals, 1, &result_index, hss));
    223   EXPECT_EQ(0u, result_index);
    224   EXPECT_TRUE(!hss[0].readable() && !hss[0].writable() && hss[0].peer_closed());
    225   EXPECT_TRUE(hss[0].never_readable() && hss[0].never_writable() &&
    226               !hss[0].never_peer_closed());
    227 }
    228 
    229 TEST_F(WaitManyTest, CloseWhileWaiting) {
    230   MessagePipe p, q;
    231 
    232   Handle handles[3] = {q.handle0.get(), q.handle1.get(), p.handle1.get()};
    233   MojoHandleSignals signals[3] = {MOJO_HANDLE_SIGNAL_READABLE,
    234                                   MOJO_HANDLE_SIGNAL_READABLE,
    235                                   MOJO_HANDLE_SIGNAL_READABLE};
    236 
    237   ThreadedRunner close_after_delay(base::Bind(
    238       [](ScopedMessagePipeHandle* handle) {
    239         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    240         handle->reset();
    241       },
    242       &p.handle1));
    243   close_after_delay.Start();
    244 
    245   size_t result_index = 0;
    246   EXPECT_EQ(MOJO_RESULT_CANCELLED,
    247             WaitMany(handles, signals, 3, &result_index));
    248   EXPECT_EQ(2u, result_index);
    249 }
    250 
    251 TEST_F(WaitManyTest, DelayedWrite) {
    252   MessagePipe p;
    253 
    254   ThreadedRunner write_after_delay(base::Bind(
    255       [](ScopedMessagePipeHandle* handle) {
    256         // Wait a little while, then write a message.
    257         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    258         WriteMessage(*handle, "wakey wakey");
    259       },
    260       &p.handle0));
    261   write_after_delay.Start();
    262 
    263   Handle handles[2] = {p.handle0.get(), p.handle1.get()};
    264   MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
    265                                   MOJO_HANDLE_SIGNAL_READABLE};
    266   size_t result_index = 0;
    267   HandleSignalsState hss[2];
    268   EXPECT_EQ(MOJO_RESULT_OK, WaitMany(handles, signals, 2, &result_index, hss));
    269   EXPECT_EQ(1u, result_index);
    270   EXPECT_TRUE(!hss[0].readable() && hss[0].writable() && !hss[0].peer_closed());
    271   EXPECT_TRUE(!hss[0].never_readable() && !hss[0].never_writable() &&
    272               !hss[0].never_peer_closed());
    273   EXPECT_TRUE(hss[1].readable() && hss[1].writable() && !hss[1].peer_closed());
    274   EXPECT_TRUE(!hss[1].never_readable() && !hss[1].never_writable() &&
    275               !hss[1].never_peer_closed());
    276 }
    277 
    278 TEST_F(WaitManyTest, DelayedPeerClosure) {
    279   MessagePipe p, q;
    280 
    281   ThreadedRunner close_after_delay(base::Bind(
    282       [](ScopedMessagePipeHandle* handle) {
    283         // Wait a little while, then close the handle.
    284         base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
    285         handle->reset();
    286       },
    287       &p.handle0));
    288   close_after_delay.Start();
    289 
    290   Handle handles[3] = {q.handle0.get(), q.handle1.get(), p.handle1.get()};
    291   MojoHandleSignals signals[3] = {MOJO_HANDLE_SIGNAL_READABLE,
    292                                   MOJO_HANDLE_SIGNAL_READABLE,
    293                                   MOJO_HANDLE_SIGNAL_READABLE};
    294   size_t result_index = 0;
    295   HandleSignalsState hss[3];
    296   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    297             WaitMany(handles, signals, 3, &result_index, hss));
    298   EXPECT_EQ(2u, result_index);
    299   EXPECT_TRUE(!hss[2].readable() && !hss[2].writable() && hss[2].peer_closed());
    300   EXPECT_TRUE(hss[2].never_readable() && hss[2].never_writable() &&
    301               !hss[2].never_peer_closed());
    302 }
    303 
    304 }  // namespace
    305 }  // namespace mojo
    306