Home | History | Annotate | Download | only in message_loop
      1 // Copyright 2012 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 "base/message_loop/message_pump_io_ios.h"
      6 
      7 #include <unistd.h>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/posix/eintr_wrapper.h"
     11 #include "base/threading/thread.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace base {
     15 
     16 class MessagePumpIOSForIOTest : public testing::Test {
     17  protected:
     18   MessagePumpIOSForIOTest()
     19       : ui_loop_(MessageLoop::TYPE_UI),
     20         io_thread_("MessagePumpIOSForIOTestIOThread") {}
     21   virtual ~MessagePumpIOSForIOTest() {}
     22 
     23   virtual void SetUp() OVERRIDE {
     24     Thread::Options options(MessageLoop::TYPE_IO, 0);
     25     ASSERT_TRUE(io_thread_.StartWithOptions(options));
     26     ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
     27     int ret = pipe(pipefds_);
     28     ASSERT_EQ(0, ret);
     29     ret = pipe(alternate_pipefds_);
     30     ASSERT_EQ(0, ret);
     31   }
     32 
     33   virtual void TearDown() OVERRIDE {
     34     if (HANDLE_EINTR(close(pipefds_[0])) < 0)
     35       PLOG(ERROR) << "close";
     36     if (HANDLE_EINTR(close(pipefds_[1])) < 0)
     37       PLOG(ERROR) << "close";
     38   }
     39 
     40   MessageLoop* ui_loop() { return &ui_loop_; }
     41   MessageLoopForIO* io_loop() const {
     42     return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
     43   }
     44 
     45   void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) {
     46     MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_,
     47         kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
     48         watcher);
     49   }
     50 
     51   int pipefds_[2];
     52   int alternate_pipefds_[2];
     53 
     54  private:
     55   MessageLoop ui_loop_;
     56   Thread io_thread_;
     57 
     58   DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest);
     59 };
     60 
     61 namespace {
     62 
     63 // Concrete implementation of MessagePumpIOSForIO::Watcher that does
     64 // nothing useful.
     65 class StupidWatcher : public MessagePumpIOSForIO::Watcher {
     66  public:
     67   virtual ~StupidWatcher() {}
     68 
     69   // base:MessagePumpIOSForIO::Watcher interface
     70   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
     71   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
     72 };
     73 
     74 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     75 
     76 // Test to make sure that we catch calling WatchFileDescriptor off of the
     77 //  wrong thread.
     78 TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) {
     79   MessagePumpIOSForIO::FileDescriptorWatcher watcher;
     80   StupidWatcher delegate;
     81 
     82   ASSERT_DEBUG_DEATH(io_loop()->WatchFileDescriptor(
     83       STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
     84       "Check failed: "
     85       "watch_file_descriptor_caller_checker_.CalledOnValidThread()");
     86 }
     87 
     88 #endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     89 
     90 class BaseWatcher : public MessagePumpIOSForIO::Watcher {
     91  public:
     92   BaseWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller)
     93       : controller_(controller) {
     94     DCHECK(controller_);
     95   }
     96   virtual ~BaseWatcher() {}
     97 
     98   // MessagePumpIOSForIO::Watcher interface
     99   virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
    100     NOTREACHED();
    101   }
    102 
    103   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    104     NOTREACHED();
    105   }
    106 
    107  protected:
    108   MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
    109 };
    110 
    111 class DeleteWatcher : public BaseWatcher {
    112  public:
    113   explicit DeleteWatcher(
    114       MessagePumpIOSForIO::FileDescriptorWatcher* controller)
    115       : BaseWatcher(controller) {}
    116 
    117   virtual ~DeleteWatcher() {
    118     DCHECK(!controller_);
    119   }
    120 
    121   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    122     DCHECK(controller_);
    123     delete controller_;
    124     controller_ = NULL;
    125   }
    126 };
    127 
    128 TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) {
    129   scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
    130   MessagePumpIOSForIO::FileDescriptorWatcher* watcher =
    131       new MessagePumpIOSForIO::FileDescriptorWatcher;
    132   DeleteWatcher delegate(watcher);
    133   pump->WatchFileDescriptor(pipefds_[1],
    134       false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate);
    135 
    136   // Spoof a callback.
    137   HandleFdIOEvent(watcher);
    138 }
    139 
    140 class StopWatcher : public BaseWatcher {
    141  public:
    142   StopWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller,
    143               MessagePumpIOSForIO* pump,
    144               int fd_to_start_watching = -1)
    145       : BaseWatcher(controller),
    146         pump_(pump),
    147         fd_to_start_watching_(fd_to_start_watching) {}
    148 
    149   virtual ~StopWatcher() {}
    150 
    151   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    152     controller_->StopWatchingFileDescriptor();
    153     if (fd_to_start_watching_ >= 0) {
    154       pump_->WatchFileDescriptor(fd_to_start_watching_,
    155           false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this);
    156     }
    157   }
    158 
    159  private:
    160   MessagePumpIOSForIO* pump_;
    161   int fd_to_start_watching_;
    162 };
    163 
    164 TEST_F(MessagePumpIOSForIOTest, StopWatcher) {
    165   scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
    166   MessagePumpIOSForIO::FileDescriptorWatcher watcher;
    167   StopWatcher delegate(&watcher, pump.get());
    168   pump->WatchFileDescriptor(pipefds_[1],
    169       false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
    170 
    171   // Spoof a callback.
    172   HandleFdIOEvent(&watcher);
    173 }
    174 
    175 TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) {
    176   scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
    177   MessagePumpIOSForIO::FileDescriptorWatcher watcher;
    178   StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]);
    179   pump->WatchFileDescriptor(pipefds_[1],
    180       false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
    181 
    182   // Spoof a callback.
    183   HandleFdIOEvent(&watcher);
    184 }
    185 
    186 }  // namespace
    187 
    188 }  // namespace base
    189